mirror of https://gitee.com/openkylin/po4a.git
Import Upstream version 0.69
This commit is contained in:
parent
60b4741885
commit
7e5a3fd886
|
@ -0,0 +1,44 @@
|
||||||
|
image:
|
||||||
|
- Visual Studio 2015
|
||||||
|
- Ubuntu
|
||||||
|
|
||||||
|
init:
|
||||||
|
- git config --global core.autocrlf true # checkout Windows-style, commit Unix-style
|
||||||
|
|
||||||
|
clone_depth: 1
|
||||||
|
|
||||||
|
environment:
|
||||||
|
PERL5LIB: /home/appveyor/perl5/lib/perl5
|
||||||
|
|
||||||
|
platform: x64
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- appveyor
|
||||||
|
|
||||||
|
skip_tags: true
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- C:\strawberry -> .appveyor.yml
|
||||||
|
|
||||||
|
install:
|
||||||
|
- cmd: if not exist "C:\strawberry" cinst strawberryperl
|
||||||
|
- cmd: set PATH=C:\strawberry\perl\bin;C:\strawberry\perl\site\bin;C:\strawberry\c\bin;C:\cygwin64\bin;%PATH%
|
||||||
|
- cmd: cd C:\projects\%APPVEYOR_PROJECT_NAME%
|
||||||
|
- cmd: rename "C:\Program Files\Git\usr\bin\sh.exe" "sh-ignored.exe" # this shell does like && and such
|
||||||
|
- sh: sudo apt-get install build-essential git libssl-dev
|
||||||
|
- sh: sudo apt-get install -y perl cpanminus opensp
|
||||||
|
- sh: export PATH=/home/appveyor/perl5/bin:$PATH
|
||||||
|
- perl -v
|
||||||
|
- sh: cpanm -v Locale::gettext # Needs libintl that I fail to install on appveyor/native
|
||||||
|
- sh: cpanm -v Text::WrapI18N
|
||||||
|
- cpanm http://search.cpan.org/CPAN/authors/id/R/RA/RAAB/SGMLSpm-1.1.tar.gz
|
||||||
|
- cpanm Unicode::GCString
|
||||||
|
- cpanm Term::ReadKey
|
||||||
|
- cpanm YAML::Tiny
|
||||||
|
- cpanm -v --installdeps --notest .
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- perl Build.PL
|
||||||
|
- ./Build test
|
|
@ -0,0 +1,40 @@
|
||||||
|
# This workflow will build po4a on linux using Module::Build
|
||||||
|
name: Build on Linux CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
tags-ignore:
|
||||||
|
- '*'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install Debian dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y liblocale-gettext-perl libtext-wrapi18n-perl libunicode-linebreak-perl libpod-parser-perl libtest-pod-perl libyaml-tiny-perl libsyntax-keyword-try-perl
|
||||||
|
sudo apt install -y cpanminus gettext docbook-xml docbook-xsl docbook xsltproc
|
||||||
|
sudo apt install -y texlive-binaries texlive-latex-base opensp libsgmls-perl
|
||||||
|
- name: Install CPAN dependencies
|
||||||
|
run: |
|
||||||
|
cpanm Locale::gettext
|
||||||
|
cpanm http://search.cpan.org/CPAN/authors/id/R/RA/RAAB/SGMLSpm-1.1.tar.gz
|
||||||
|
cpanm Text::WrapI18N
|
||||||
|
cpanm Unicode::GCString
|
||||||
|
|
||||||
|
cpanm -v --installdeps --notest .
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
perl Build.PL
|
||||||
|
COLUMNS=120 ./Build verbose=1
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./Build test verbose=1
|
|
@ -0,0 +1,46 @@
|
||||||
|
# This does not work because the tests rely heavily on the diff utility
|
||||||
|
# that is not available on Windows. We could change it to use a Perl
|
||||||
|
# implementation of diff. PR would be very welcomed here.
|
||||||
|
|
||||||
|
# This workflow will build po4a on linux using Module::Build
|
||||||
|
name: Build on Windows CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
tags-ignore:
|
||||||
|
- '*'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: shogo82148/actions-setup-perl@v1
|
||||||
|
with:
|
||||||
|
#perl-version: '5.32'
|
||||||
|
distribution: strawberry
|
||||||
|
install-modules-with: cpanm
|
||||||
|
install-modules: Term::ReadKey Unicode::GCString Syntax::Keyword::Try http://search.cpan.org/CPAN/authors/id/R/RA/RAAB/SGMLSpm-1.1.tar.gz YAML::Tiny
|
||||||
|
# Locale::gettext and Text::WrapI18N seem broken on windows.
|
||||||
|
- run: perl -V
|
||||||
|
# - name: Install Debian dependencies
|
||||||
|
# run: |
|
||||||
|
# sudo apt update
|
||||||
|
# sudo apt install -y liblocale-gettext-perl libtext-wrapi18n-perl libunicode-linebreak-perl libtest-pod-perl libyaml-tiny-perl libsyntax-keyword-try-perl
|
||||||
|
# sudo apt install -y cpanminus gettext docbook-xml docbook-xsl docbook xsltproc
|
||||||
|
# sudo apt install -y texlive-binaries texlive-latex-base opensp libsgmls-perl
|
||||||
|
|
||||||
|
- run: cpanm -v --installdeps --notest .
|
||||||
|
|
||||||
|
- name: Create the Build script
|
||||||
|
run: perl Build.PL
|
||||||
|
- name: Actual build
|
||||||
|
run: ./Build verbose=1
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: ./Build test verbose=1
|
|
@ -0,0 +1,10 @@
|
||||||
|
*~
|
||||||
|
Build
|
||||||
|
META.yml
|
||||||
|
META.json
|
||||||
|
MYMETA.json
|
||||||
|
MYMETA.yml
|
||||||
|
_build/
|
||||||
|
blib/
|
||||||
|
t/tmp/
|
||||||
|
.tidyall.d/
|
|
@ -0,0 +1,5 @@
|
||||||
|
[PerlTidy]
|
||||||
|
select = po4a{,-gettextize,-normalize,-translate,-updatepo}
|
||||||
|
select = lib/**/*.pm
|
||||||
|
select = t/*.{t,pm}
|
||||||
|
argv = -utf8 -log -noll --maximum-line-length=120 --iterations=2 --cuddled-else
|
|
@ -0,0 +1,41 @@
|
||||||
|
language: perl
|
||||||
|
dist: bionic
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- liblocale-gettext-perl
|
||||||
|
- libtext-wrapi18n-perl
|
||||||
|
- libunicode-linebreak-perl
|
||||||
|
- libtest-pod-perl
|
||||||
|
- gettext
|
||||||
|
- docbook-xml
|
||||||
|
- docbook-xsl
|
||||||
|
- docbook
|
||||||
|
- xsltproc
|
||||||
|
- texlive-binaries
|
||||||
|
- texlive-latex-base
|
||||||
|
- opensp
|
||||||
|
- libsgmls-perl
|
||||||
|
- docbook
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- cpanm Locale::gettext
|
||||||
|
- cpanm http://search.cpan.org/CPAN/authors/id/R/RA/RAAB/SGMLSpm-1.1.tar.gz
|
||||||
|
- cpanm Text::WrapI18N
|
||||||
|
- cpanm Unicode::GCString
|
||||||
|
|
||||||
|
install:
|
||||||
|
- cpanm -v --installdeps --notest .
|
||||||
|
|
||||||
|
script:
|
||||||
|
- perl Build.PL
|
||||||
|
- COLUMNS=120 ./Build verbose=1
|
||||||
|
- ./Build test verbose=1
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_success: change
|
||||||
|
on_failure: always
|
||||||
|
irc:
|
||||||
|
channels:
|
||||||
|
- "irc.debian.org#po4a"
|
|
@ -0,0 +1,3 @@
|
||||||
|
[weblate]
|
||||||
|
url = https://hosted.weblate.org/api/
|
||||||
|
translation = po4a/po4a
|
2
Build.PL
2
Build.PL
|
@ -35,7 +35,7 @@ my $build = Po4aBuilder->new
|
||||||
dist_abstract => 'Maintain the translations of your documentation with ease (PO for anything)',
|
dist_abstract => 'Maintain the translations of your documentation with ease (PO for anything)',
|
||||||
dist_author => ['Martin Quinson (mquinson#debian.org)',
|
dist_author => ['Martin Quinson (mquinson#debian.org)',
|
||||||
'Denis Barbier <barbier@linuxfr.org>',
|
'Denis Barbier <barbier@linuxfr.org>',
|
||||||
'Nicolas Francois <nicolas.francois@centraliens.net>',
|
'Nicolas François <nicolas.francois@centraliens.net>',
|
||||||
'Neil Williams <linux@codehelp.co.uk>']
|
'Neil Williams <linux@codehelp.co.uk>']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
79
MANIFEST
79
MANIFEST
|
@ -64,6 +64,7 @@ po/bin/hu.po
|
||||||
po/bin/id.po
|
po/bin/id.po
|
||||||
po/bin/it.po
|
po/bin/it.po
|
||||||
po/bin/ja.po
|
po/bin/ja.po
|
||||||
|
po/bin/ka.po
|
||||||
po/bin/kn.po
|
po/bin/kn.po
|
||||||
po/bin/ko.po
|
po/bin/ko.po
|
||||||
po/bin/nb.po
|
po/bin/nb.po
|
||||||
|
@ -101,6 +102,7 @@ po/pod/ru.po
|
||||||
po/pod/sr_Cyrl.po
|
po/pod/sr_Cyrl.po
|
||||||
po/pod/uk.po
|
po/pod/uk.po
|
||||||
po/pod/zh_CHS.po
|
po/pod/zh_CHS.po
|
||||||
|
po/pod/zh_Hant.po
|
||||||
msguntypot
|
msguntypot
|
||||||
po4a
|
po4a
|
||||||
po4a-gettextize
|
po4a-gettextize
|
||||||
|
@ -239,6 +241,13 @@ t/cfg/single-podirectory-emptypot/po/fr.po
|
||||||
t/cfg/single-podirectory-emptypot/po/single.pot
|
t/cfg/single-podirectory-emptypot/po/single.pot
|
||||||
t/cfg/single-podirectory-emptypot/po4a.conf
|
t/cfg/single-podirectory-emptypot/po4a.conf
|
||||||
t/cfg/single-podirectory-emptypot/single.man.1
|
t/cfg/single-podirectory-emptypot/single.man.1
|
||||||
|
t/cfg/single-podirectory-emptypot-emptypo/_fr.po.expected
|
||||||
|
t/cfg/single-podirectory-emptypot-emptypo/_output
|
||||||
|
t/cfg/single-podirectory-emptypot-emptypo/_single.pot.expected
|
||||||
|
t/cfg/single-podirectory-emptypot-emptypo/fr.po
|
||||||
|
t/cfg/single-podirectory-emptypot-emptypo/po4a.conf
|
||||||
|
t/cfg/single-podirectory-emptypot-emptypo/single.man.1
|
||||||
|
t/cfg/single-podirectory-emptypot-emptypo/single.pot
|
||||||
t/cfg/multiple-fuzzy/po4a.conf
|
t/cfg/multiple-fuzzy/po4a.conf
|
||||||
t/cfg/multiple-fuzzy/multiple.it.po
|
t/cfg/multiple-fuzzy/multiple.it.po
|
||||||
t/cfg/multiple-fuzzy/multiple.man.de.1
|
t/cfg/multiple-fuzzy/multiple.man.de.1
|
||||||
|
@ -668,6 +677,11 @@ t/fmt/asciidoc/Footnotes.norm
|
||||||
t/fmt/asciidoc/Footnotes.po
|
t/fmt/asciidoc/Footnotes.po
|
||||||
t/fmt/asciidoc/Footnotes.pot
|
t/fmt/asciidoc/Footnotes.pot
|
||||||
t/fmt/asciidoc/Footnotes.trans
|
t/fmt/asciidoc/Footnotes.trans
|
||||||
|
t/fmt/asciidoc/LineBreak.adoc
|
||||||
|
t/fmt/asciidoc/LineBreak.norm
|
||||||
|
t/fmt/asciidoc/LineBreak.po
|
||||||
|
t/fmt/asciidoc/LineBreak.pot
|
||||||
|
t/fmt/asciidoc/LineBreak.trans
|
||||||
t/fmt/asciidoc/Lists.adoc
|
t/fmt/asciidoc/Lists.adoc
|
||||||
t/fmt/asciidoc/Lists.norm
|
t/fmt/asciidoc/Lists.norm
|
||||||
t/fmt/asciidoc/Lists.norm.stderr
|
t/fmt/asciidoc/Lists.norm.stderr
|
||||||
|
@ -675,6 +689,11 @@ t/fmt/asciidoc/Lists.po
|
||||||
t/fmt/asciidoc/Lists.pot
|
t/fmt/asciidoc/Lists.pot
|
||||||
t/fmt/asciidoc/Lists.trans
|
t/fmt/asciidoc/Lists.trans
|
||||||
t/fmt/asciidoc/Lists.trans.stderr
|
t/fmt/asciidoc/Lists.trans.stderr
|
||||||
|
t/fmt/asciidoc/MacroIncludesHugo.adoc
|
||||||
|
t/fmt/asciidoc/MacroIncludesHugo.norm
|
||||||
|
t/fmt/asciidoc/MacroIncludesHugo.po
|
||||||
|
t/fmt/asciidoc/MacroIncludesHugo.pot
|
||||||
|
t/fmt/asciidoc/MacroIncludesHugo.trans
|
||||||
t/fmt/asciidoc/NoImageTarget.adoc
|
t/fmt/asciidoc/NoImageTarget.adoc
|
||||||
t/fmt/asciidoc/NoImageTarget.norm
|
t/fmt/asciidoc/NoImageTarget.norm
|
||||||
t/fmt/asciidoc/NoImageTarget.po
|
t/fmt/asciidoc/NoImageTarget.po
|
||||||
|
@ -724,6 +743,11 @@ t/fmt/asciidoc/YamlFrontMatter.norm
|
||||||
t/fmt/asciidoc/YamlFrontMatter.po
|
t/fmt/asciidoc/YamlFrontMatter.po
|
||||||
t/fmt/asciidoc/YamlFrontMatter.pot
|
t/fmt/asciidoc/YamlFrontMatter.pot
|
||||||
t/fmt/asciidoc/YamlFrontMatter.trans
|
t/fmt/asciidoc/YamlFrontMatter.trans
|
||||||
|
t/fmt/asciidoc/YamlFrontMatter_KeysPaths.adoc
|
||||||
|
t/fmt/asciidoc/YamlFrontMatter_KeysPaths.norm
|
||||||
|
t/fmt/asciidoc/YamlFrontMatter_KeysPaths.po
|
||||||
|
t/fmt/asciidoc/YamlFrontMatter_KeysPaths.pot
|
||||||
|
t/fmt/asciidoc/YamlFrontMatter_KeysPaths.trans
|
||||||
t/fmt/asciidoc/YamlFrontMatter_Option.adoc
|
t/fmt/asciidoc/YamlFrontMatter_Option.adoc
|
||||||
t/fmt/asciidoc/YamlFrontMatter_Option.norm
|
t/fmt/asciidoc/YamlFrontMatter_Option.norm
|
||||||
t/fmt/asciidoc/YamlFrontMatter_Option.po
|
t/fmt/asciidoc/YamlFrontMatter_Option.po
|
||||||
|
@ -795,6 +819,20 @@ t/fmt/man/macros.norm
|
||||||
t/fmt/man/macros.po
|
t/fmt/man/macros.po
|
||||||
t/fmt/man/macros.pot
|
t/fmt/man/macros.pot
|
||||||
t/fmt/man/macros.trans
|
t/fmt/man/macros.trans
|
||||||
|
t/fmt/man/macro-def.man
|
||||||
|
t/fmt/man/macro-def.norm
|
||||||
|
t/fmt/man/macro-def.po
|
||||||
|
t/fmt/man/macro-def.pot
|
||||||
|
t/fmt/man/macro-def.stderr-missing-behavior
|
||||||
|
t/fmt/man/macro-def.trans
|
||||||
|
t/fmt/man/macro-defuse.man
|
||||||
|
t/fmt/man/macro-defuse.norm
|
||||||
|
t/fmt/man/macro-defuse.po
|
||||||
|
t/fmt/man/macro-defuse.po-noarg
|
||||||
|
t/fmt/man/macro-defuse.pot
|
||||||
|
t/fmt/man/macro-defuse.pot-noarg
|
||||||
|
t/fmt/man/macro-defuse.stderr-missing-behavior
|
||||||
|
t/fmt/man/macro-defuse.trans
|
||||||
t/fmt/man/mdoc.man
|
t/fmt/man/mdoc.man
|
||||||
t/fmt/man/mdoc.norm
|
t/fmt/man/mdoc.norm
|
||||||
t/fmt/man/mdoc.po
|
t/fmt/man/mdoc.po
|
||||||
|
@ -985,14 +1023,26 @@ t/fmt/txt-markdown/Rules.pot
|
||||||
t/fmt/txt-markdown/Rules.trans
|
t/fmt/txt-markdown/Rules.trans
|
||||||
t/fmt/txt-markdown/YamlFrontMatter.md
|
t/fmt/txt-markdown/YamlFrontMatter.md
|
||||||
t/fmt/txt-markdown/YamlFrontMatter.norm
|
t/fmt/txt-markdown/YamlFrontMatter.norm
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter.po
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter.pot
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter.trans
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_fake.md
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_fake.norm
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_fake.norm.stderr
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_fake.po
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_fake.pot
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_fake.trans
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_fake.trans.stderr
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_KeysPaths.md
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_KeysPaths.norm
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_KeysPaths.po
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_KeysPaths.pot
|
||||||
|
t/fmt/txt-markdown/YamlFrontMatter_KeysPaths.trans
|
||||||
t/fmt/txt-markdown/YamlFrontMatter_Options.md
|
t/fmt/txt-markdown/YamlFrontMatter_Options.md
|
||||||
t/fmt/txt-markdown/YamlFrontMatter_Options.norm
|
t/fmt/txt-markdown/YamlFrontMatter_Options.norm
|
||||||
t/fmt/txt-markdown/YamlFrontMatter_Options.po
|
t/fmt/txt-markdown/YamlFrontMatter_Options.po
|
||||||
t/fmt/txt-markdown/YamlFrontMatter_Options.pot
|
t/fmt/txt-markdown/YamlFrontMatter_Options.pot
|
||||||
t/fmt/txt-markdown/YamlFrontMatter_Options.trans
|
t/fmt/txt-markdown/YamlFrontMatter_Options.trans
|
||||||
t/fmt/txt-markdown/YamlFrontMatter.po
|
|
||||||
t/fmt/txt-markdown/YamlFrontMatter.pot
|
|
||||||
t/fmt/txt-markdown/YamlFrontMatter.trans
|
|
||||||
t/fmt/wml/basic.norm
|
t/fmt/wml/basic.norm
|
||||||
t/fmt/wml/basic.po
|
t/fmt/wml/basic.po
|
||||||
t/fmt/wml/basic.pot
|
t/fmt/wml/basic.pot
|
||||||
|
@ -1014,6 +1064,11 @@ t/fmt/xhtml/includessi.norm
|
||||||
t/fmt/xhtml/includessi.po
|
t/fmt/xhtml/includessi.po
|
||||||
t/fmt/xhtml/includessi.pot
|
t/fmt/xhtml/includessi.pot
|
||||||
t/fmt/xhtml/includessi.trans
|
t/fmt/xhtml/includessi.trans
|
||||||
|
t/fmt/xhtml/table.html
|
||||||
|
t/fmt/xhtml/table.norm
|
||||||
|
t/fmt/xhtml/table.po
|
||||||
|
t/fmt/xhtml/table.pot
|
||||||
|
t/fmt/xhtml/table.trans
|
||||||
t/fmt/xml/attribute-novalue.desc
|
t/fmt/xml/attribute-novalue.desc
|
||||||
t/fmt/xml/attribute-novalue.norm
|
t/fmt/xml/attribute-novalue.norm
|
||||||
t/fmt/xml/attribute-novalue.po
|
t/fmt/xml/attribute-novalue.po
|
||||||
|
@ -1045,12 +1100,22 @@ t/fmt/xml-dia/transl.norm
|
||||||
t/fmt/xml-dia/transl.po
|
t/fmt/xml-dia/transl.po
|
||||||
t/fmt/xml-dia/transl.pot
|
t/fmt/xml-dia/transl.pot
|
||||||
t/fmt/xml-dia/transl.trans
|
t/fmt/xml-dia/transl.trans
|
||||||
|
t/fmt/xml/inside-foldattribute.norm
|
||||||
|
t/fmt/xml/inside-foldattribute.po
|
||||||
|
t/fmt/xml/inside-foldattribute.pot
|
||||||
|
t/fmt/xml/inside-foldattribute.trans
|
||||||
|
t/fmt/xml/inside-foldattribute.xml
|
||||||
t/fmt/xml/options.desc
|
t/fmt/xml/options.desc
|
||||||
t/fmt/xml/options.norm
|
t/fmt/xml/options.norm
|
||||||
t/fmt/xml/options.po
|
t/fmt/xml/options.po
|
||||||
t/fmt/xml/options.pot
|
t/fmt/xml/options.pot
|
||||||
t/fmt/xml/options.trans
|
t/fmt/xml/options.trans
|
||||||
t/fmt/xml/options.xml
|
t/fmt/xml/options.xml
|
||||||
|
t/fmt/xml/placeholder-empty.norm
|
||||||
|
t/fmt/xml/placeholder-empty.po
|
||||||
|
t/fmt/xml/placeholder-empty.pot
|
||||||
|
t/fmt/xml/placeholder-empty.trans
|
||||||
|
t/fmt/xml/placeholder-empty.xml
|
||||||
t/fmt/yaml/basic.norm
|
t/fmt/yaml/basic.norm
|
||||||
t/fmt/yaml/basic.po
|
t/fmt/yaml/basic.po
|
||||||
t/fmt/yaml/basic.pot
|
t/fmt/yaml/basic.pot
|
||||||
|
@ -1081,6 +1146,13 @@ t/fmt/yaml/utf8.po
|
||||||
t/fmt/yaml/utf8.pot
|
t/fmt/yaml/utf8.pot
|
||||||
t/fmt/yaml/utf8.trans
|
t/fmt/yaml/utf8.trans
|
||||||
t/fmt/yaml/utf8.yaml
|
t/fmt/yaml/utf8.yaml
|
||||||
|
t/gettextize/TEST_OK.md
|
||||||
|
t/gettextize/test_dups.err
|
||||||
|
t/gettextize/test_dups.md
|
||||||
|
t/gettextize/test_dups.po
|
||||||
|
t/gettextize/test_ok.err
|
||||||
|
t/gettextize/test_ok.md
|
||||||
|
t/gettextize/test_ok.po
|
||||||
|
|
||||||
t/add.t
|
t/add.t
|
||||||
t/cfg-args.t
|
t/cfg-args.t
|
||||||
|
@ -1107,6 +1179,7 @@ t/fmt-xhtml.t
|
||||||
t/fmt-xml-dia.t
|
t/fmt-xml-dia.t
|
||||||
t/fmt-xml.t
|
t/fmt-xml.t
|
||||||
t/fmt-yaml.t
|
t/fmt-yaml.t
|
||||||
|
t/gettextize.t
|
||||||
t/pod.t
|
t/pod.t
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
^\.git/
|
||||||
|
^\.gitignore
|
||||||
|
^\.svn/
|
||||||
|
\.bak$
|
||||||
|
~$
|
||||||
|
.travis.yml
|
||||||
|
.weblate
|
||||||
|
.appveyor.yml
|
||||||
|
\.tidyall.d/
|
||||||
|
\.tidyallrc
|
||||||
|
\.github/
|
||||||
|
|
||||||
|
po/bin/zanata.xml
|
||||||
|
po/pod/zanata.xml
|
||||||
|
|
||||||
|
# Avoid configuration metadata file
|
||||||
|
^MYMETA\.
|
||||||
|
|
||||||
|
# Avoid Module::Build generated and utility files.
|
||||||
|
\bBuild$
|
||||||
|
\bBuild.bat$
|
||||||
|
\b_build
|
||||||
|
\bBuild.COM$
|
||||||
|
\bBUILD.COM$
|
||||||
|
\bbuild.com$
|
||||||
|
^MANIFEST\.SKIP
|
||||||
|
|
||||||
|
# Avoid archives of this distribution
|
||||||
|
\bpo4a-[\d\.\_]+
|
||||||
|
|
||||||
|
^blib/
|
||||||
|
^lib/Locale/Po4a/Debconf.pm
|
||||||
|
^lib/Locale/Po4a/NewsDebian.pm
|
||||||
|
^extension/
|
||||||
|
^testsuite/
|
||||||
|
^t/tmp/
|
||||||
|
^MYMETA\.yml$
|
||||||
|
^MYMETA\.json$
|
||||||
|
^share/Makefile$
|
||||||
|
^share/doc/.*/po4a.*\.xml
|
134
META.json
134
META.json
|
@ -1,134 +0,0 @@
|
||||||
{
|
|
||||||
"abstract" : "Maintain the translations of your documentation with ease (PO for anything)",
|
|
||||||
"author" : [
|
|
||||||
"Martin Quinson (mquinson#debian.org)",
|
|
||||||
"Denis Barbier <barbier@linuxfr.org>",
|
|
||||||
"Nicolas Francois <nicolas.francois@centraliens.net>",
|
|
||||||
"Neil Williams <linux@codehelp.co.uk>"
|
|
||||||
],
|
|
||||||
"dynamic_config" : 1,
|
|
||||||
"generated_by" : "Module::Build version 0.4231",
|
|
||||||
"license" : [
|
|
||||||
"gpl_1"
|
|
||||||
],
|
|
||||||
"meta-spec" : {
|
|
||||||
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
|
|
||||||
"version" : 2
|
|
||||||
},
|
|
||||||
"name" : "po4a",
|
|
||||||
"prereqs" : {
|
|
||||||
"configure" : {
|
|
||||||
"requires" : {
|
|
||||||
"Module::Build" : "0.42"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"runtime" : {
|
|
||||||
"recommends" : {
|
|
||||||
"Locale::gettext" : "1.01",
|
|
||||||
"SGMLS" : "0",
|
|
||||||
"Term::ReadKey" : "0",
|
|
||||||
"Text::WrapI18N" : "0",
|
|
||||||
"Unicode::GCString" : "0",
|
|
||||||
"YAML::Tiny" : "0"
|
|
||||||
},
|
|
||||||
"requires" : {
|
|
||||||
"Pod::Parser" : "0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test" : {
|
|
||||||
"requires" : {
|
|
||||||
"SGMLS" : "0",
|
|
||||||
"Unicode::GCString" : "0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"provides" : {
|
|
||||||
"Locale::Po4a::AsciiDoc" : {
|
|
||||||
"file" : "lib/Locale/Po4a/AsciiDoc.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::BibTeX" : {
|
|
||||||
"file" : "lib/Locale/Po4a/BibTeX.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Chooser" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Chooser.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Common" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Common.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Debconf" : {
|
|
||||||
"file" : "lib/Locale/Po4a/InProgress/Debconf.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Dia" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Dia.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Docbook" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Docbook.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Guide" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Guide.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Halibut" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Halibut.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Ini" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Ini.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::KernelHelp" : {
|
|
||||||
"file" : "lib/Locale/Po4a/KernelHelp.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::LaTeX" : {
|
|
||||||
"file" : "lib/Locale/Po4a/LaTeX.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Man" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Man.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::NewsDebian" : {
|
|
||||||
"file" : "lib/Locale/Po4a/InProgress/NewsDebian.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Po" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Po.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Pod" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Pod.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::RubyDoc" : {
|
|
||||||
"file" : "lib/Locale/Po4a/RubyDoc.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Sgml" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Sgml.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::TeX" : {
|
|
||||||
"file" : "lib/Locale/Po4a/TeX.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Texinfo" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Texinfo.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Text" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Text.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::TransTractor" : {
|
|
||||||
"file" : "lib/Locale/Po4a/TransTractor.pm",
|
|
||||||
"version" : "0.66"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Wml" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Wml.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Xhtml" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Xhtml.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Xml" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Xml.pm"
|
|
||||||
},
|
|
||||||
"Locale::Po4a::Yaml" : {
|
|
||||||
"file" : "lib/Locale/Po4a/Yaml.pm"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"release_status" : "stable",
|
|
||||||
"resources" : {
|
|
||||||
"license" : [
|
|
||||||
"http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"version" : "0.66",
|
|
||||||
"x_serialization_backend" : "JSON::PP version 4.04"
|
|
||||||
}
|
|
86
META.yml
86
META.yml
|
@ -1,86 +0,0 @@
|
||||||
---
|
|
||||||
abstract: 'Maintain the translations of your documentation with ease (PO for anything)'
|
|
||||||
author:
|
|
||||||
- 'Martin Quinson (mquinson#debian.org)'
|
|
||||||
- 'Denis Barbier <barbier@linuxfr.org>'
|
|
||||||
- 'Nicolas Francois <nicolas.francois@centraliens.net>'
|
|
||||||
- 'Neil Williams <linux@codehelp.co.uk>'
|
|
||||||
build_requires:
|
|
||||||
SGMLS: '0'
|
|
||||||
Unicode::GCString: '0'
|
|
||||||
configure_requires:
|
|
||||||
Module::Build: '0.42'
|
|
||||||
dynamic_config: 1
|
|
||||||
generated_by: 'Module::Build version 0.4231, CPAN::Meta::Converter version 2.150010'
|
|
||||||
license: gpl
|
|
||||||
meta-spec:
|
|
||||||
url: http://module-build.sourceforge.net/META-spec-v1.4.html
|
|
||||||
version: '1.4'
|
|
||||||
name: po4a
|
|
||||||
provides:
|
|
||||||
Locale::Po4a::AsciiDoc:
|
|
||||||
file: lib/Locale/Po4a/AsciiDoc.pm
|
|
||||||
Locale::Po4a::BibTeX:
|
|
||||||
file: lib/Locale/Po4a/BibTeX.pm
|
|
||||||
Locale::Po4a::Chooser:
|
|
||||||
file: lib/Locale/Po4a/Chooser.pm
|
|
||||||
Locale::Po4a::Common:
|
|
||||||
file: lib/Locale/Po4a/Common.pm
|
|
||||||
Locale::Po4a::Debconf:
|
|
||||||
file: lib/Locale/Po4a/InProgress/Debconf.pm
|
|
||||||
Locale::Po4a::Dia:
|
|
||||||
file: lib/Locale/Po4a/Dia.pm
|
|
||||||
Locale::Po4a::Docbook:
|
|
||||||
file: lib/Locale/Po4a/Docbook.pm
|
|
||||||
Locale::Po4a::Guide:
|
|
||||||
file: lib/Locale/Po4a/Guide.pm
|
|
||||||
Locale::Po4a::Halibut:
|
|
||||||
file: lib/Locale/Po4a/Halibut.pm
|
|
||||||
Locale::Po4a::Ini:
|
|
||||||
file: lib/Locale/Po4a/Ini.pm
|
|
||||||
Locale::Po4a::KernelHelp:
|
|
||||||
file: lib/Locale/Po4a/KernelHelp.pm
|
|
||||||
Locale::Po4a::LaTeX:
|
|
||||||
file: lib/Locale/Po4a/LaTeX.pm
|
|
||||||
Locale::Po4a::Man:
|
|
||||||
file: lib/Locale/Po4a/Man.pm
|
|
||||||
Locale::Po4a::NewsDebian:
|
|
||||||
file: lib/Locale/Po4a/InProgress/NewsDebian.pm
|
|
||||||
Locale::Po4a::Po:
|
|
||||||
file: lib/Locale/Po4a/Po.pm
|
|
||||||
Locale::Po4a::Pod:
|
|
||||||
file: lib/Locale/Po4a/Pod.pm
|
|
||||||
Locale::Po4a::RubyDoc:
|
|
||||||
file: lib/Locale/Po4a/RubyDoc.pm
|
|
||||||
Locale::Po4a::Sgml:
|
|
||||||
file: lib/Locale/Po4a/Sgml.pm
|
|
||||||
Locale::Po4a::TeX:
|
|
||||||
file: lib/Locale/Po4a/TeX.pm
|
|
||||||
Locale::Po4a::Texinfo:
|
|
||||||
file: lib/Locale/Po4a/Texinfo.pm
|
|
||||||
Locale::Po4a::Text:
|
|
||||||
file: lib/Locale/Po4a/Text.pm
|
|
||||||
Locale::Po4a::TransTractor:
|
|
||||||
file: lib/Locale/Po4a/TransTractor.pm
|
|
||||||
version: '0.66'
|
|
||||||
Locale::Po4a::Wml:
|
|
||||||
file: lib/Locale/Po4a/Wml.pm
|
|
||||||
Locale::Po4a::Xhtml:
|
|
||||||
file: lib/Locale/Po4a/Xhtml.pm
|
|
||||||
Locale::Po4a::Xml:
|
|
||||||
file: lib/Locale/Po4a/Xml.pm
|
|
||||||
Locale::Po4a::Yaml:
|
|
||||||
file: lib/Locale/Po4a/Yaml.pm
|
|
||||||
recommends:
|
|
||||||
Locale::gettext: '1.01'
|
|
||||||
SGMLS: '0'
|
|
||||||
Term::ReadKey: '0'
|
|
||||||
Text::WrapI18N: '0'
|
|
||||||
Unicode::GCString: '0'
|
|
||||||
YAML::Tiny: '0'
|
|
||||||
requires:
|
|
||||||
Pod::Parser: '0'
|
|
||||||
resources:
|
|
||||||
license: http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt
|
|
||||||
version: '0.66'
|
|
||||||
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
|
|
230
NEWS
230
NEWS
|
@ -1,6 +1,234 @@
|
||||||
This file presents the major changes of each version, focusing on
|
This file presents the major changes of each version, focusing on
|
||||||
user-visible changes while the day to day changes are in the git logs.
|
user-visible changes while the day to day changes are in the git logs.
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
___ __ ___
|
||||||
|
__ __/ _ \ / /_ / _ \
|
||||||
|
\ \ / / | | | '_ \ (_) | Happy New Year release.
|
||||||
|
\ V /| |_| | (_) \__, |
|
||||||
|
\_/ \___(_)___/ /_/ (Released on 2023/01/01)
|
||||||
|
|
||||||
|
Markdown:
|
||||||
|
* Parts of a fenced divs are now translated separately (GitHub's #381)
|
||||||
|
|
||||||
|
YAML and Yaml Front Matter:
|
||||||
|
* Use the implementation of YFM to parse YAML files too.
|
||||||
|
- This reduces the code dupplication, and brings the nice features over:
|
||||||
|
Numbers and arrays are not quoted anymore in Yaml files, as it should be.
|
||||||
|
- This adds the yfm_paths option to Markdown and Asciidoc YFM,
|
||||||
|
fixing GitHub's #392 along the way.
|
||||||
|
- Please note that '-o keys' is now case-sensitive in Yaml documents.
|
||||||
|
* Do not translate nor quote booleans, so that they are not treated as string.
|
||||||
|
Thanks Gissmo for GitHub's PR #393, even if I had to rework it quite a bit.
|
||||||
|
|
||||||
|
XML:
|
||||||
|
* Correctly handle placeholders of empty elements (GitHub's #389)
|
||||||
|
* Translate attributes within attribute-folded inline and placeholder (GH #391)
|
||||||
|
alt attribute of <img> can be properly handled with:
|
||||||
|
-o 'attributes=<image>alt' -o 'inline=<image>' -o foldattributes
|
||||||
|
* Thanks k-yaegashi for the pull request fixing both issues
|
||||||
|
|
||||||
|
Project organization:
|
||||||
|
* Do not leak the generation date in our manpages (GitHub's #387)
|
||||||
|
Thanks Arnout Engelen for the pull request.
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
* New translation: Georgian, thanks Temuri Doghonadze.
|
||||||
|
* Updated: Dutch, thanks Frans Spiesschaert.
|
||||||
|
* Updated: French, thanks Jérémie Tarot & Brandelune.
|
||||||
|
* Updated: Italian, thanks Marco Ciampa.
|
||||||
|
* Updated: Japanese, thanks gemmaro.
|
||||||
|
* Updated: Portuguese, thanks Hugo Carvalho.
|
||||||
|
* Updated: Portuguese (Brazil), thanks Rafael Fontenelle.
|
||||||
|
* Updated: Ukrainian, thanks Yuri Chornoivan (українська).
|
||||||
|
|
||||||
|
Status of the binary translation:
|
||||||
|
* 100%: fr, it, nl, pt_BR, uk.
|
||||||
|
* >95%: eo (96%), nb (96%), pt (99%), sr_Cyrl (99%).
|
||||||
|
* >90%: de (94%), es (94%), hr (94%), hu (92%), ru (93%), zh_CN (94%), zh_Hant (94%).
|
||||||
|
* >70%: id (77%), sv (72%).
|
||||||
|
* >50%: cs (57%), da (62%), et (67%), eu (56%), ja (63%), pl (62%), sl (56%), vi (67%).
|
||||||
|
* >33%: ca (45%).
|
||||||
|
* Starting: ace (2%), af (7%), ar (14%), ka (16%), kn (7%), ko (18%), zh_HK (3%).
|
||||||
|
|
||||||
|
Status of the documentation translation:
|
||||||
|
* 100%: it, uk.
|
||||||
|
* >95%: de (98%), fr (99%), ja (96%), nl (99%), sr_Cyrl (98%).
|
||||||
|
* >90%: pt (93%), pt_BR (94%), zh_CHS (94%), zh_Hant (94%).
|
||||||
|
* >80%: es (83%).
|
||||||
|
* >50%: pl (66%), ru (64%).
|
||||||
|
* >33%: ca (43%).
|
||||||
|
* Starting: eo (2%), hr (0%), hu (0%), nb (4%).
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
___ __ ___
|
||||||
|
__ __/ _ \ / /_ ( _ )
|
||||||
|
\ \ / / | | | '_ \ / _ \ High Hopes release.
|
||||||
|
\ V /| |_| | (_) | (_) |
|
||||||
|
\_/ \___(_)___/ \___/ (Released on 2022/09/04)
|
||||||
|
|
||||||
|
|
||||||
|
This release dedication is here to remind you that Hope is always important.
|
||||||
|
Plus, the song of that name by Pink Floyd also deserves a dedication.
|
||||||
|
|
||||||
|
Project organization:
|
||||||
|
* Add a deprecation warning to po4a-translate and po4a-updatepo stating
|
||||||
|
that po4a is the prefered interface.
|
||||||
|
* Rewrite the po4a-gettextize documentation (Debian's #1016695) [Mt].
|
||||||
|
* Rewrite the intro of po4a doc, and add a Quick start tutorial [Mt].
|
||||||
|
|
||||||
|
gettextization:
|
||||||
|
* Rework completely the deduplication of msgids introduced in v0.67.
|
||||||
|
- Instead of adding spaces and require the users to merge them
|
||||||
|
manually after an extremely painful analysis of the produced file,
|
||||||
|
automatically merge the msgstr together.
|
||||||
|
- The result will look something like:
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "hello"
|
||||||
|
msgstr ""
|
||||||
|
"#-#-#-#-# file reference 1 (type: Title #) #-#-#-#-#\n"
|
||||||
|
"HELLO\n"
|
||||||
|
"#-#-#-#-# file reference 2 (type: Title ##) #-#-#-#-#\n"
|
||||||
|
"SUBTITLE\n"
|
||||||
|
|
||||||
|
- Closes Debian's #1017742, that was asking for help in the review [Mt].
|
||||||
|
|
||||||
|
Markdown:
|
||||||
|
* Allow lists to start the line with no leading spaces before the '-'
|
||||||
|
sign (Github's #378). This uncovers a bug in our test suite that
|
||||||
|
was enforcing the buggy behavior :( [Mt]
|
||||||
|
* Properly deal with fenced div blocks (Github's #381) [Mt]
|
||||||
|
|
||||||
|
Man:
|
||||||
|
* Bold text should never be wrapped as groff seems to reset the font
|
||||||
|
on new line (Debian's #1016753) [Mt].
|
||||||
|
* Properly deal with comments around macro definitions [Mt]
|
||||||
|
(Debian's #1017837).
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
* Updated: Croatian, thanks Milo Ivir.
|
||||||
|
* Updated: Esperanto, thanks Marco Ciampa.
|
||||||
|
* Updated: German, thanks Helge Kreutzmann.
|
||||||
|
* Updated: Italian, thanks Marco Ciampa.
|
||||||
|
* Updated: Japanese, thanks gemmaro.
|
||||||
|
* Updated: Portuguese, thanks Hugo Carvalho.
|
||||||
|
* Updated: Serbian (cyrillic), thanks Ivan Pesic.
|
||||||
|
* Updated: Ukrainian, thanks Yuri Chornoivan (українська) & Artem.
|
||||||
|
|
||||||
|
Status of the binary translation:
|
||||||
|
* 100%: de, pt, sr_Cyrl, uk.
|
||||||
|
* >95%: eo (97%), es (95%), fr (97%), hr (95%), it (97%), nb (97%),
|
||||||
|
nl (95%), pt_BR (97%), zh_CN (95%), zh_Hant (95%).
|
||||||
|
* >90%: hu (93%), ru (93%).
|
||||||
|
* >70%: id (78%), sv (72%).
|
||||||
|
* >50%: cs (58%), da (62%), et (68%), eu (56%), ja (62%), pl (62%),
|
||||||
|
sl (56%), vi (67%).
|
||||||
|
* >33%: ca (45%).
|
||||||
|
* Starting: ace (2%), af (7%), ar (14%), kn (7%), ko (18%), zh_HK (3%).
|
||||||
|
|
||||||
|
Status of the documentation translation:
|
||||||
|
* 100%: it, uk.
|
||||||
|
* >95%: de (99%), fr (95%), pt_BR (95%), sr_Cyrl (99%).
|
||||||
|
* >90%: nl (94%), pt (94%), zh_CHS (94%), zh_Hant (94%).
|
||||||
|
* >80%: es (83%).
|
||||||
|
* >70%: ja (72%).
|
||||||
|
* >50%: pl (66%), ru (64%).
|
||||||
|
* >33%: ca (43%).
|
||||||
|
* Starting: eo (2%), hr (0%), hu (0%), nb (4%).
|
||||||
|
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
___ __ _____
|
||||||
|
__ __/ _ \ / /|___ |
|
||||||
|
\ \ / / | | | '_ \ / / The Maryna Viazovska Release.
|
||||||
|
\ V /| |_| | (_) / /
|
||||||
|
\_/ \___(_)___/_/ (Released on 2022/07/14)
|
||||||
|
|
||||||
|
|
||||||
|
Maryna Viazovska was recently awarded a Fields Medal for her work on
|
||||||
|
the sphere-packing problem in higher dimension.
|
||||||
|
|
||||||
|
Asciidoc:
|
||||||
|
* Support Hugo shortcode on macros (GitHub's #352) [Danilo G. Baio]
|
||||||
|
* Support automatically numbered callouts (GitHub's #351) [J.N. Avila]
|
||||||
|
* Support line breaks (GitHub's #199) [J.N. Avila]
|
||||||
|
|
||||||
|
gettextization:
|
||||||
|
* Deduplicate the msgids, to prevent the structure desynchronizations
|
||||||
|
when the same string is used at several locations, with mismatching types.
|
||||||
|
(GitHub's #334) [mquinson]
|
||||||
|
* Add some tests for the gettextization feature. [mquinson]
|
||||||
|
|
||||||
|
po4a-translate:
|
||||||
|
* Do not check whether the po file is uptodate, as it's impossible to do
|
||||||
|
that correctly when several master files are merged in the same POT.
|
||||||
|
(GitHub's #156) [mquinson]
|
||||||
|
|
||||||
|
Man:
|
||||||
|
* Improve the error message when using '.de', '.if', '.ie' to hint about
|
||||||
|
the option 'groff_code=verbatim|translate' (GitHub's #361) [mquinson]
|
||||||
|
* Implement '.el' (else branch) as translate_joined [mquinson]
|
||||||
|
* Implement '.de1' (define with no check) as '.de' [mquinson]
|
||||||
|
* Implement '.dei', '.dei1' (define with subst) (Debian's #710678) [MQ]
|
||||||
|
* Implement '.it' (input trap) as untranslated (GitHub's #339) [mquinson]
|
||||||
|
* Make a sensible warning when user-defined macros are not explained to po4a
|
||||||
|
with the 'untranslated' option and friends. [mquinson]
|
||||||
|
|
||||||
|
Markdown:
|
||||||
|
* New option 'yfm_lenient' to proceed even if the YAML Front Matter parser fails.
|
||||||
|
Useful when your file starts with an horizontal ruler that is not a YFM.
|
||||||
|
(GitHub's #365) [mquinson]
|
||||||
|
This introduces a NEW DEPENDENCY: Syntax::Keyword::Try
|
||||||
|
* Do not quote the YFM lists to not break them (GitHub's #304) [mquinson].
|
||||||
|
Thanks @dbaio for the analysis and @ynojima for an initial patch in doc-l10n-kit.
|
||||||
|
|
||||||
|
xHTML:
|
||||||
|
* Add a test for tables and stop claiming that they may be broken
|
||||||
|
(GitHub's #366, thanks Petter Reinholdtsen).
|
||||||
|
|
||||||
|
Other bug fixes:
|
||||||
|
* Hide an ugly warning about uninitialized string (GitHub's #360) [mquinson]
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
* Updated: Chinese (simplified and traditional), thanks taotieren.
|
||||||
|
* Updated: Dutch, thanks Frans Spiesschaert.
|
||||||
|
* Updated: Esperanto, thanks Marco Ciampa.
|
||||||
|
* Updated: French, thanks jmichault and Jérémie Tarot.
|
||||||
|
* Updated: German, thanks Helge Kreutzmann.
|
||||||
|
* Updated: Italian, thanks Marco Ciampa.
|
||||||
|
* Updated: Norwegian Bokmål, thanks Petter Reinholdtsen.
|
||||||
|
* Updated: Portuguese, thanks Hugo Carvalho & Silvério Santos.
|
||||||
|
* Updated: Portuguese (Brazil), thanks Rafael Fontenelle and Luiz Fernando Ranghetti.
|
||||||
|
* Updated: Serbian (cyrillic), thanks Ivan Pesic.
|
||||||
|
* Updated: Spanish, thanks Francisco Serrador.
|
||||||
|
* Updated: Ukrainian, thanks Yuri Chornoivan (українська).
|
||||||
|
* Updated: Vietnamese, thanks Trần Ngọc Quân.
|
||||||
|
|
||||||
|
Status of the binary translation:
|
||||||
|
* 5 languages = 100%: de, fr, nb, pt_BR, sr_Cyrl.
|
||||||
|
* 11 languages >= 95%: eo (97%), es (97%), hr (97%), hu (95%),
|
||||||
|
it (97%), nl (97%), pt (97%), ru (96%),
|
||||||
|
uk (98%), zh_CN (97%), zh_Hant(97%).
|
||||||
|
* 1 language >= 80%: id (80%).
|
||||||
|
* 1 language >= 70%: sv (74%).
|
||||||
|
* 8 languages >= 50%: cs (59%), da (62%), et (69%), eu (58%),
|
||||||
|
ja (64%), pl (64%), sl (57%), vi (69%).
|
||||||
|
* 1 language >= 33%: ca (46%).
|
||||||
|
* 6 starting languages: ace (2%), af (7%), ar (14%), kn (7%),
|
||||||
|
ko(19%), zh_HK (3%).
|
||||||
|
|
||||||
|
Status of the documentation translation:
|
||||||
|
* 2 languages = 100%: fr, uk.
|
||||||
|
* 8 languages >= 95%: de (98%), it (99%), nl (98%), pt (97%),
|
||||||
|
pt_BR (99%), sr_Cyrl (99%), zh_CHS (98%),
|
||||||
|
zh_Hant (98%).
|
||||||
|
* 1 language >= 80%: es (87%).
|
||||||
|
* 1 language >= 70%: ja (74%).
|
||||||
|
* 2 languages >= 50%: pl (67%), ru (68%).
|
||||||
|
* 1 language >= 33%: ca (44%).
|
||||||
|
* 4 starting languages: eo (2%), hr (0%), hu (0%), nb (4%).
|
||||||
|
|
||||||
=======================================================================
|
=======================================================================
|
||||||
___ __ __
|
___ __ __
|
||||||
__ __/ _ \ / /_ / /_
|
__ __/ _ \ / /_ / /_
|
||||||
|
@ -61,7 +289,7 @@ Status of the documentation translation:
|
||||||
1 language >= 70%: es (78%).
|
1 language >= 70%: es (78%).
|
||||||
3 languages >= 50%: ja (69%), pl (69%), ru (69%).
|
3 languages >= 50%: ja (69%), pl (69%), ru (69%).
|
||||||
1 language >= 33%: ca (44%).
|
1 language >= 33%: ca (44%).
|
||||||
4 starting languages: eo (2%), hr (0%), hu (0%), nb (3%).
|
4 starting languages: eo (2%), hr (0%), hu (0%), nb (3%).
|
||||||
|
|
||||||
=======================================================================
|
=======================================================================
|
||||||
___ __ ____
|
___ __ ____
|
||||||
|
|
|
@ -14,8 +14,8 @@ sub ACTION_build {
|
||||||
$self->depends_on('code');
|
$self->depends_on('code');
|
||||||
$self->depends_on('docs');
|
$self->depends_on('docs');
|
||||||
$self->depends_on('distmeta'); # regenerate META.yml
|
$self->depends_on('distmeta'); # regenerate META.yml
|
||||||
$self->depends_on('man');
|
$self->depends_on('man') unless ($^O eq 'MSWin32');
|
||||||
$self->depends_on('postats');
|
$self->depends_on('postats') unless ($^O eq 'MSWin32');
|
||||||
}
|
}
|
||||||
|
|
||||||
sub make_files_writable {
|
sub make_files_writable {
|
||||||
|
@ -234,27 +234,29 @@ sub ACTION_man {
|
||||||
}
|
}
|
||||||
$parser->parse_from_file ($file, $out);
|
$parser->parse_from_file ($file, $out);
|
||||||
|
|
||||||
system("gzip -9 -f $out") and die;
|
system("gzip -9 -n -f $out") and die;
|
||||||
unlink "$file" || die;
|
unlink "$file" || die;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Install the manpages written in XML DocBook
|
if ($^O ne 'MSWin32') {
|
||||||
foreach $file (qw(po4a-display-man.xml po4a-display-pod.xml)) {
|
# Install the manpages written in XML DocBook
|
||||||
copy ( File::Spec->catdir("share", "doc", $file), $man1path) or die;
|
foreach $file (qw(po4a-display-man.xml po4a-display-pod.xml)) {
|
||||||
}
|
copy ( File::Spec->catdir("share", "doc", $file), $man1path) or die;
|
||||||
foreach $file (@{$self->rscan_dir($manpath, qr{\.xml$})}) {
|
}
|
||||||
if ($file =~ m,(.*/man(.))/([^/]*)\.xml$,) {
|
foreach $file (@{$self->rscan_dir($manpath, qr{\.xml$})}) {
|
||||||
my ($outdir, $section, $outfile) = ($1, $2, $3);
|
if ($file =~ m,(.*/man(.))/([^/]*)\.xml$,) {
|
||||||
if (-e "/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl") { # Location on Debian at least
|
my ($outdir, $section, $outfile) = ($1, $2, $3);
|
||||||
print "Convert $outdir/$outfile.$section (local docbook.xsl file). ";
|
if (-e "/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl") { # Location on Debian at least
|
||||||
system("xsltproc -o $outdir/$outfile.$section --nonet /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl $file") and die;
|
print "Convert $outdir/$outfile.$section (local docbook.xsl file). ";
|
||||||
} else { # Not found locally, use the XSL file online
|
system("xsltproc -o $outdir/$outfile.$section --nonet /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl $file") and die;
|
||||||
print "Convert $outdir/$outfile.$section (online docbook.xsl file). ";
|
} else { # Not found locally, use the XSL file online
|
||||||
system("xsltproc -o $outdir/$outfile.$section --nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $file") and die;
|
print "Convert $outdir/$outfile.$section (online docbook.xsl file). ";
|
||||||
}
|
system("xsltproc -o $outdir/$outfile.$section --nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $file") and die;
|
||||||
system ("gzip -9 -f $outdir/$outfile.$section") and die;
|
}
|
||||||
|
system ("gzip -9 -n -f $outdir/$outfile.$section") and die;
|
||||||
|
}
|
||||||
|
unlink "$file" || die;
|
||||||
}
|
}
|
||||||
unlink "$file" || die;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Introduction to Po4a
|
# Introduction to Po4a
|
||||||
|
|
||||||
[![Build Status](https://img.shields.io/github/workflow/status/mquinson/po4a/Build%20on%20Linux%20CI?style=flat-square)](https://github.com/mquinson/po4a/actions/workflows/linux.yml)
|
[![Build Status](https://img.shields.io/github/actions/workflow/status/mquinson/po4a/linux.yml?style=flat-square&branch=main)](https://github.com/mquinson/po4a/actions/workflows/linux.yml)
|
||||||
[![First Timers Friendly](https://img.shields.io/badge/Beginners-Welcome-brightgreen?style=flat-square)](https://www.firsttimersonly.com)
|
[![First Timers Friendly](https://img.shields.io/badge/Beginners-Welcome-brightgreen?style=flat-square)](https://www.firsttimersonly.com)
|
||||||
|
|
||||||
The goal of po4a (PO for anything) project is to ease translations (and
|
The goal of po4a (PO for anything) project is to ease translations (and
|
||||||
|
@ -130,7 +130,7 @@ the git tree), use the PERLLIB environment variable as such:
|
||||||
This program is free software; you may redistribute it and/or modify it
|
This program is free software; you may redistribute it and/or modify it
|
||||||
under the terms of GPL (see COPYING file).
|
under the terms of GPL (see COPYING file).
|
||||||
|
|
||||||
Copyright © 2002-2021 by SPI, inc.
|
Copyright © 2002-2022 by SPI, inc.
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
- Denis Barbier <barbier@linuxfr.org>
|
- Denis Barbier <barbier@linuxfr.org>
|
||||||
|
|
|
@ -3684,10 +3684,10 @@ po4a (0.18-1) unstable; urgency=low
|
||||||
"Displays and keeps" macros. This was needed to deal with the man pages
|
"Displays and keeps" macros. This was needed to deal with the man pages
|
||||||
of shadow and dpkg.
|
of shadow and dpkg.
|
||||||
- No groff nbsp (ie '\ ') on the last pos of the line, or groff adds an
|
- No groff nbsp (ie '\ ') on the last pos of the line, or groff adds an
|
||||||
extra space. Thanks to Nicolas Francois for the info.
|
extra space. Thanks to Nicolas François for the info.
|
||||||
- Convert \- to - on the fly. The asteatic of the printed man page may
|
- Convert \- to - on the fly. The asteatic of the printed man page may
|
||||||
suffer (a hyphen is different of a minus sign in ps/pdf), but makes
|
suffer (a hyphen is different of a minus sign in ps/pdf), but makes
|
||||||
translator's life easier. Thanks to Nicolas Francois for the expertise.
|
translator's life easier. Thanks to Nicolas François for the expertise.
|
||||||
- Stick to groff_man(7) intead of man(7), and consider that when IP is
|
- Stick to groff_man(7) intead of man(7), and consider that when IP is
|
||||||
given only one argument, that's the designator (which we have to
|
given only one argument, that's the designator (which we have to
|
||||||
translate) instead of the column indentation. Thanks Francois.
|
translate) instead of the column indentation. Thanks Francois.
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
po4a (0.66-ok1) yangtze; urgency=medium
|
|
||||||
|
|
||||||
* Build for openKylin.
|
|
||||||
|
|
||||||
-- openKylinBot <openKylinBot@openkylin.com> Mon, 25 Apr 2022 22:03:04 +0800
|
|
|
@ -1,64 +0,0 @@
|
||||||
Source: po4a
|
|
||||||
Section: text
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: Martin Quinson <mquinson@debian.org>
|
|
||||||
Uploaders: Jonas Smedegaard <dr@jones.dk>,
|
|
||||||
Denis Barbier <barbier@debian.org>,
|
|
||||||
Dr. Tobias Quathamer <toddy@debian.org>
|
|
||||||
Standards-Version: 4.6.0
|
|
||||||
Build-Depends-Indep: docbook,
|
|
||||||
docbook-xml,
|
|
||||||
docbook-xsl,
|
|
||||||
gettext,
|
|
||||||
libpod-parser-perl,
|
|
||||||
libsgmls-perl,
|
|
||||||
libterm-readkey-perl,
|
|
||||||
libunicode-linebreak-perl,
|
|
||||||
libyaml-tiny-perl,
|
|
||||||
opensp,
|
|
||||||
perl,
|
|
||||||
texlive-binaries,
|
|
||||||
texlive-latex-base,
|
|
||||||
xsltproc
|
|
||||||
Build-Depends:
|
|
||||||
debhelper-compat (= 13),
|
|
||||||
libmodule-build-perl
|
|
||||||
Rules-Requires-Root: no
|
|
||||||
Homepage: https://po4a.org/
|
|
||||||
Vcs-Git: https://salsa.debian.org/debian/po4a.git
|
|
||||||
Vcs-Browser: https://salsa.debian.org/debian/po4a
|
|
||||||
|
|
||||||
Package: po4a
|
|
||||||
Architecture: all
|
|
||||||
Multi-Arch: foreign
|
|
||||||
Depends: gettext,
|
|
||||||
libpod-parser-perl (>= 1.63),
|
|
||||||
libsgmls-perl,
|
|
||||||
libyaml-tiny-perl,
|
|
||||||
opensp,
|
|
||||||
${misc:Depends},
|
|
||||||
${perl:Depends}
|
|
||||||
Recommends: liblocale-gettext-perl,
|
|
||||||
libterm-readkey-perl,
|
|
||||||
libtext-wrapi18n-perl,
|
|
||||||
libunicode-linebreak-perl
|
|
||||||
Description: tools to ease the translation of documentation
|
|
||||||
po4a eases the translation of documentation and other textual document.
|
|
||||||
Even more interestingly, it makes it easy to maintain these
|
|
||||||
translations when the original document changes. This is done by
|
|
||||||
using the gettext tools in this new domain.
|
|
||||||
.
|
|
||||||
This package contains the main libraries of po4a, and the necessary
|
|
||||||
sub-modules to handle the following formats:
|
|
||||||
.
|
|
||||||
- Dia: uncompressed Dia diagrams.
|
|
||||||
- INI: the INI format
|
|
||||||
- KernelHelp: Help messages of each kernel compilation option.
|
|
||||||
- LaTeX: generic TeX or LaTeX format.
|
|
||||||
- Man: either roff or mdoc format.
|
|
||||||
- POD: Perl documentation format.
|
|
||||||
- SGML: either DebianDoc or DocBook DTD.
|
|
||||||
- RubyDoc: Ruby documentation format.
|
|
||||||
- Texinfo: the info page format.
|
|
||||||
- XML: very configurable (preconfigured for DocBook, XHTML, Guide, WML).
|
|
||||||
- Yaml: Yaml documents.
|
|
|
@ -1,50 +0,0 @@
|
||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Upstream-Name: po4a
|
|
||||||
Upstream-Contact: Martin Quinson <mquinson@debian.org>
|
|
||||||
Source: https://po4a.org
|
|
||||||
|
|
||||||
Files: *
|
|
||||||
Copyright: © 2002-2022 Martin Quinson <mquinson@debian.org>
|
|
||||||
© 2002-2022 Software in the Public Interest, Inc.
|
|
||||||
© 1995 David Megginson <dmeggins@aix1.uottawa.ca>
|
|
||||||
© 2004 Jordi Vilalta <jvprat@gmail.com>
|
|
||||||
© 2005-2009 Nicolas FRANÇOIS <nicolas.francois@centraliens.net>
|
|
||||||
© 2006 BitDefender
|
|
||||||
© 2009 Neil Williams <linux@codehelp.co.uk>
|
|
||||||
© 2018 Zero King (https://github.com/l2dy)
|
|
||||||
License: GPL-2.0+
|
|
||||||
|
|
||||||
Files: lib/Locale/Po4a/RubyDoc.pm
|
|
||||||
Copyright: © 2016-2017 Francesco Poli <invernomuto@paranoici.org>
|
|
||||||
© 2004 MoonWolf <moonwolf@moonwolf.com>
|
|
||||||
© 2011-2012 Youhei SASAKI <uwabami@gfd-dennou.org>
|
|
||||||
License: GPL-2.0+
|
|
||||||
|
|
||||||
Files: lib/Locale/Po4a/Yaml.pm
|
|
||||||
Copyright: © 2018 Brian Exelbierd
|
|
||||||
License: GPL-2.0+
|
|
||||||
|
|
||||||
Files: debian/*
|
|
||||||
Copyright: © 2002-2022 Martin Quinson <mquinson@debian.org>
|
|
||||||
© 2005-2009 Nicolas FRANÇOIS <nicolas.francois@centraliens.net>
|
|
||||||
© 2009 Neil Williams <linux@codehelp.co.uk>
|
|
||||||
© 2003-2013 Denis Barbier <barbier@debian.org>
|
|
||||||
© 2018-2020 Dr. Tobias Quathamer <toddy@debian.org>
|
|
||||||
License: GPL-2.0+
|
|
||||||
|
|
||||||
License: GPL-2.0+
|
|
||||||
This package is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
.
|
|
||||||
This package is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
.
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General
|
|
||||||
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
|
|
|
@ -1,4 +0,0 @@
|
||||||
usr/bin
|
|
||||||
usr/share/man/fr/man1
|
|
||||||
usr/share/man/man1
|
|
||||||
usr/share/perl5/Locale/Po4a
|
|
|
@ -1,4 +0,0 @@
|
||||||
CONTRIBUTING.md
|
|
||||||
README.maintainers
|
|
||||||
README.md
|
|
||||||
NEWS
|
|
|
@ -1,91 +0,0 @@
|
||||||
#!/usr/bin/perl -w
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
# Copyright 2009 by Javier Fernández-Sanguino Peña <jfs@debian.org>
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Quick and dirty script to compare two msgids (when using PO files
|
|
||||||
# generated with --previous) with wdiff to find the differences between
|
|
||||||
# them.
|
|
||||||
# Usage: perl compare-msgids.pl < XX.po
|
|
||||||
|
|
||||||
|
|
||||||
use File::Temp;
|
|
||||||
|
|
||||||
my $DIFF1 = new File::Temp(TEMPLATE => "compare-msgids.XXXXXX");
|
|
||||||
my $DIFF2 = new File::Temp(TEMPLATE => "compare-msgids.XXXXXX");
|
|
||||||
|
|
||||||
my $fileh="";
|
|
||||||
|
|
||||||
my $diffblock = 0; # Does the current block has a --previous string?
|
|
||||||
my $nowrap = 0; # Can the current be rewrapped?
|
|
||||||
my $ref = ""; # Line reference for the current block
|
|
||||||
|
|
||||||
while (my $line = <STDIN>) {
|
|
||||||
$fileh="";
|
|
||||||
chomp $line;
|
|
||||||
|
|
||||||
$ref .= $line."\n" if $line =~ /^#: /;
|
|
||||||
$ref = "" if ($line eq "");
|
|
||||||
|
|
||||||
if ( $diffblock and $line =~ /^msgstr/ ) {
|
|
||||||
$diffblock = 0;
|
|
||||||
$nowrap = 0;
|
|
||||||
print $DIFF1 "\n\n";
|
|
||||||
print $DIFF2 "\n\n";
|
|
||||||
}
|
|
||||||
$diffblock = 1 if ( $line =~ /^\#\| msgid/ ) ;
|
|
||||||
$nowrap = 1 if ( $line =~ /^#,.*no-wrap/ ) ;
|
|
||||||
|
|
||||||
if ($diffblock) {
|
|
||||||
if (length $ref) {
|
|
||||||
print $DIFF1 $ref."\n";
|
|
||||||
print $DIFF1 $ref."\n";
|
|
||||||
print $DIFF2 $ref."\n";
|
|
||||||
$ref = "";
|
|
||||||
}
|
|
||||||
$fileh = $DIFF1 if ( $line =~ /^\#\| msgid/ ) ;
|
|
||||||
$fileh = $DIFF1 if ( $line =~ /^\#\| "/ ) ;
|
|
||||||
$fileh = $DIFF2 if ( $line =~ /^msgid/ ) ;
|
|
||||||
$fileh = $DIFF2 if ( $line =~ /^"/ ) ;
|
|
||||||
|
|
||||||
if ($fileh ne "") {
|
|
||||||
$line =~ s/^\#\| //;
|
|
||||||
|
|
||||||
print $fileh "\n" if ( $line =~ /^msgid_plural "/);
|
|
||||||
|
|
||||||
$line =~ s/^"//;
|
|
||||||
$line =~ s/^msgid "//;
|
|
||||||
$line =~ s/^msgid_plural "//;
|
|
||||||
$line =~ s/"$//;
|
|
||||||
|
|
||||||
print $fileh $line;
|
|
||||||
print $fileh "\n" if ($nowrap and $line =~ m/\\n$/);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close $DIFF1; close $DIFF2;
|
|
||||||
|
|
||||||
system ("wdiff", "-3", $DIFF1->filename, $DIFF2->filename)
|
|
||||||
or die "Failed to run wdiff.";
|
|
||||||
|
|
||||||
|
|
||||||
exit;
|
|
|
@ -1,10 +0,0 @@
|
||||||
# See https://salsa.debian.org/salsa-ci-team/pipeline
|
|
||||||
|
|
||||||
---
|
|
||||||
include:
|
|
||||||
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
|
|
||||||
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
|
|
||||||
|
|
||||||
variables:
|
|
||||||
SALSA_CI_REPROTEST_ENABLE_DIFFOSCOPE: 1
|
|
||||||
SALSA_CI_DISABLE_BUILD_PACKAGE_ANY: '1'
|
|
|
@ -1 +0,0 @@
|
||||||
debian/examples/compare-msgids.pl
|
|
|
@ -1,10 +0,0 @@
|
||||||
#!/usr/bin/make -f
|
|
||||||
|
|
||||||
%:
|
|
||||||
dh $@
|
|
||||||
|
|
||||||
# Replace the shebang line in perl scripts to
|
|
||||||
# comply with Policy 10.4
|
|
||||||
override_dh_auto_install:
|
|
||||||
dh_auto_install
|
|
||||||
sed -i -e "1 s,^.*perl.*$$,#!/usr/bin/perl," $(CURDIR)/debian/po4a/usr/bin/*
|
|
|
@ -1 +0,0 @@
|
||||||
3.0 (native)
|
|
|
@ -1,3 +0,0 @@
|
||||||
version=4
|
|
||||||
opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/po4a-$1\.tar\.gz/ \
|
|
||||||
https://github.com//mquinson/po4a/tags .*/v?(\d\S+)\.tar\.gz
|
|
|
@ -247,7 +247,7 @@ is difficult to keep the PO files up to date and build the documentation files
|
||||||
correctly. As an answer, a all-in-one tool was provided: L<po4a(1)>. This tool
|
correctly. As an answer, a all-in-one tool was provided: L<po4a(1)>. This tool
|
||||||
takes a configuration file describing the structure of the translation project:
|
takes a configuration file describing the structure of the translation project:
|
||||||
the location of the PO files, the list of files to translate, and the options to
|
the location of the PO files, the list of files to translate, and the options to
|
||||||
use, and it fully automatizes the process. When you invoke L<po4a(1)>, it both
|
use, and it fully automates the process. When you invoke L<po4a(1)>, it both
|
||||||
updates the PO files and regenerate the translation files that need to. If
|
updates the PO files and regenerate the translation files that need to. If
|
||||||
everything is already up to date, L<po4a(1)> does not change any file.
|
everything is already up to date, L<po4a(1)> does not change any file.
|
||||||
|
|
||||||
|
@ -671,7 +671,8 @@ is a French onomatopoetic that we use in place of yuck :) I may have a strange s
|
||||||
|
|
||||||
=head2 What about the other translation tools for documentation using gettext?
|
=head2 What about the other translation tools for documentation using gettext?
|
||||||
|
|
||||||
As far as I know, there are only two of them:
|
There are a few of them. Here is a possibly incomplete list, and more tools are
|
||||||
|
coming at the horizon.
|
||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
|
@ -691,6 +692,19 @@ This program done by Denis Barbier is a sort of precursor of the po4a SGML
|
||||||
module, which more or less deprecates it. As the name says, it handles only
|
module, which more or less deprecates it. As the name says, it handles only
|
||||||
the DebianDoc DTD, which is more or less a deprecated DTD.
|
the DebianDoc DTD, which is more or less a deprecated DTD.
|
||||||
|
|
||||||
|
=item B<xml2po.py>
|
||||||
|
|
||||||
|
Used by the GIMP Documentation Team since 2004, works quite well even if,
|
||||||
|
as the name suggests, only with XML files and needs specially configured
|
||||||
|
makefiles.
|
||||||
|
|
||||||
|
=item B<Sphinx>
|
||||||
|
|
||||||
|
The Sphinx Documentation Project also uses gettext extensively to manage its
|
||||||
|
translations. Unfortunately, it works only for a few text formats, rest and
|
||||||
|
markdown, although it is perhaps the only tool that does this managing the whole
|
||||||
|
translation process.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
The main advantages of po4a over them are the ease of extra content addition
|
The main advantages of po4a over them are the ease of extra content addition
|
||||||
|
|
|
@ -107,17 +107,18 @@ Switch parsing rules to compatibility with different tools. Available options ar
|
||||||
"asciidoc" or "asciidoctor". Asciidoctor has stricter parsing rules, such as
|
"asciidoc" or "asciidoctor". Asciidoctor has stricter parsing rules, such as
|
||||||
equality of length of opening and closing block fences.
|
equality of length of opening and closing block fences.
|
||||||
|
|
||||||
=item B<yfm_keys>
|
|
||||||
|
|
||||||
Comma-separated list of keys to process for translation in the YAML Front Matter
|
|
||||||
section. All other keys are skipped. Keys are matched with a case-insensitive
|
|
||||||
match. Array values are always translated, unless the B<yfm_skip_array> option
|
|
||||||
is provided.
|
|
||||||
|
|
||||||
=item B<nolinting>
|
=item B<nolinting>
|
||||||
|
|
||||||
Disable linting messages. When the source code cannot be fixed for clearer document structure, these messages are useless.
|
Disable linting messages. When the source code cannot be fixed for clearer document structure, these messages are useless.
|
||||||
|
|
||||||
|
=item B<yfm_keys>
|
||||||
|
|
||||||
|
Comma-separated list of keys to process for translation in the YAML Front Matter
|
||||||
|
section. All other keys are skipped. Keys are matched with a case-sensitive
|
||||||
|
match. If B<yfm_paths> and B<yfm_keys> are used together, values are included if
|
||||||
|
they are matched by at least one of the options. Array values are always translated,
|
||||||
|
unless the B<yfm_skip_array> option is provided.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
my %yfm_keys = ();
|
my %yfm_keys = ();
|
||||||
|
@ -130,6 +131,19 @@ Do not translate array values in the YAML Front Matter section.
|
||||||
|
|
||||||
my $yfm_skip_array = 0;
|
my $yfm_skip_array = 0;
|
||||||
|
|
||||||
|
=item B<yfm_paths>
|
||||||
|
|
||||||
|
Comma-separated list of hash paths to process for extraction in the YAML
|
||||||
|
Front Matter section, all other paths are skipped. Paths are matched with a
|
||||||
|
case-sensitive match. If B<yfm_paths> and B<yfm_keys> are used together,
|
||||||
|
values are included if they are matched by at least one of the options.
|
||||||
|
Arrays values are always returned unless the B<yfm_skip_array> option is
|
||||||
|
provided.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
my %yfm_paths = ();
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 INLINE CUSTOMIZATION
|
=head1 INLINE CUSTOMIZATION
|
||||||
|
@ -142,12 +156,12 @@ The following commands are recognized:
|
||||||
|
|
||||||
=item B<//po4a: macro >I<name>B<[>I<attribute list>B<]>
|
=item B<//po4a: macro >I<name>B<[>I<attribute list>B<]>
|
||||||
|
|
||||||
This permits to describe in detail the parameters of a B<macro>;
|
This describes in detail the parameters of a B<macro>;
|
||||||
I<name> must be a valid macro name, and it ends with an underscore
|
I<name> must be a valid macro name, and it ends with an underscore
|
||||||
if the target must be translated.
|
if the target must be translated.
|
||||||
|
|
||||||
The I<attribute list> argument is a comma separated list which
|
The I<attribute list> argument is a comma separated list which
|
||||||
contains informations about translatable arguments. This list contains
|
contains information about translatable arguments. This list contains
|
||||||
either numbers, to define positional parameters, or named attributes.
|
either numbers, to define positional parameters, or named attributes.
|
||||||
|
|
||||||
If a plus sign (B<+>) is prepended to I<name>, then the macro and its
|
If a plus sign (B<+>) is prepended to I<name>, then the macro and its
|
||||||
|
@ -156,11 +170,11 @@ attribute list in this case, but brackets must be present.
|
||||||
|
|
||||||
=item B<//po4a: style >B<[>I<attribute list>B<]>
|
=item B<//po4a: style >B<[>I<attribute list>B<]>
|
||||||
|
|
||||||
This permits to describe in detail which attributes of a style must
|
This describes in detail which attributes of a style must
|
||||||
be translated.
|
be translated.
|
||||||
|
|
||||||
The I<attribute list> argument is a comma separated list which
|
The I<attribute list> argument is a comma separated list which
|
||||||
contains informations about translatable arguments. This list contains
|
contains information about translatable arguments. This list contains
|
||||||
either numbers, to define positional parameters, or named attributes.
|
either numbers, to define positional parameters, or named attributes.
|
||||||
The first attribute is the style name, it will not be translated.
|
The first attribute is the style name, it will not be translated.
|
||||||
|
|
||||||
|
@ -205,6 +219,7 @@ sub initialize {
|
||||||
$self->{options}{'compat'} = 'asciidoc';
|
$self->{options}{'compat'} = 'asciidoc';
|
||||||
$self->{options}{'yfm_keys'} = '';
|
$self->{options}{'yfm_keys'} = '';
|
||||||
$self->{options}{'yfm_skip_array'} = 0;
|
$self->{options}{'yfm_skip_array'} = 0;
|
||||||
|
$self->{options}{'yfm_paths'} = '';
|
||||||
$self->{options}{'nolinting'} = 0;
|
$self->{options}{'nolinting'} = 0;
|
||||||
|
|
||||||
foreach my $opt ( keys %options ) {
|
foreach my $opt ( keys %options ) {
|
||||||
|
@ -228,8 +243,11 @@ sub initialize {
|
||||||
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||||
$yfm_keys{$_} = 1
|
$yfm_keys{$_} = 1
|
||||||
} ( split( ',', $self->{options}{'yfm_keys'} ) );
|
} ( split( ',', $self->{options}{'yfm_keys'} ) );
|
||||||
|
map {
|
||||||
|
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||||
|
$yfm_paths{$_} = 1
|
||||||
|
} ( split( ',', $self->{options}{'yfm_paths'} ) );
|
||||||
|
|
||||||
# map { print STDERR "key $_\n"; } (keys %yfm_keys);
|
|
||||||
$yfm_skip_array = $self->{options}{'yfm_skip_array'};
|
$yfm_skip_array = $self->{options}{'yfm_skip_array'};
|
||||||
|
|
||||||
$self->{translate} = {
|
$self->{translate} = {
|
||||||
|
@ -349,6 +367,7 @@ BEGIN {
|
||||||
my $UnicodeGCString_available = 0;
|
my $UnicodeGCString_available = 0;
|
||||||
$UnicodeGCString_available = 1 if ( eval { require Unicode::GCString } );
|
$UnicodeGCString_available = 1 if ( eval { require Unicode::GCString } );
|
||||||
eval {
|
eval {
|
||||||
|
|
||||||
sub chars($$$) {
|
sub chars($$$) {
|
||||||
my $text = shift;
|
my $text = shift;
|
||||||
my $encoder = shift;
|
my $encoder = shift;
|
||||||
|
@ -372,6 +391,22 @@ BEGIN {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub translate {
|
||||||
|
my ( $self, $str, $ref, $type ) = @_;
|
||||||
|
my (%options) = @_;
|
||||||
|
if ( ($options{'wrap'}==1) && ($str =~ / \+\n/) ) {
|
||||||
|
$options{'wrap'} = 0;
|
||||||
|
$str =~ s/([^+])\n/$1 /g;
|
||||||
|
$str =~ s/ \+\n/\n/g;
|
||||||
|
$str = $self->SUPER::translate( $str, $ref, $type, %options);
|
||||||
|
$str =~ s/\n/ +\n/g;
|
||||||
|
$options{'wrap'} = 1;
|
||||||
|
} else {
|
||||||
|
$str = $self->SUPER::translate( $str, $ref, $type, %options );
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
sub parse {
|
sub parse {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ( $line, $ref ) = $self->shiftline();
|
my ( $line, $ref ) = $self->shiftline();
|
||||||
|
@ -389,7 +424,8 @@ sub parse {
|
||||||
my $yamlarray = YAML::Tiny->read_string($yfm)
|
my $yamlarray = YAML::Tiny->read_string($yfm)
|
||||||
|| die "Couldn't read YAML Front Matter ($!)\n$yfm\n";
|
|| die "Couldn't read YAML Front Matter ($!)\n$yfm\n";
|
||||||
|
|
||||||
$self->handle_yaml( $ref, $yamlarray, \%yfm_keys, $yfm_skip_array );
|
$self->handle_yaml( 1, $ref, $yamlarray, \%yfm_keys, $yfm_skip_array, \%yfm_paths );
|
||||||
|
$self->pushline("---\n");
|
||||||
|
|
||||||
( $line, $ref ) = $self->shiftline(); # Pass the final '---'
|
( $line, $ref ) = $self->shiftline(); # Pass the final '---'
|
||||||
}
|
}
|
||||||
|
@ -439,7 +475,7 @@ sub parse {
|
||||||
and ( $self->{type} eq "Table" )
|
and ( $self->{type} eq "Table" )
|
||||||
and ( $line !~ m/^\|===/ )
|
and ( $line !~ m/^\|===/ )
|
||||||
and ( $self->{options}{"tablecells"} )
|
and ( $self->{options}{"tablecells"} )
|
||||||
and (not defined $self->{disabletablecells}))
|
and ( not defined $self->{disabletablecells} ) )
|
||||||
{
|
{
|
||||||
# inside a table, and we should split per cell
|
# inside a table, and we should split per cell
|
||||||
my $new_line = "";
|
my $new_line = "";
|
||||||
|
@ -463,8 +499,10 @@ sub parse {
|
||||||
my @parts = map { ( $_, shift @texts ) } @seps;
|
my @parts = map { ( $_, shift @texts ) } @seps;
|
||||||
foreach my $part (@parts) {
|
foreach my $part (@parts) {
|
||||||
if ( not defined $part ) {
|
if ( not defined $part ) {
|
||||||
# allows concatenation and will be stripped anyway
|
|
||||||
$part = " "; }
|
# allows concatenation and will be stripped anyway
|
||||||
|
$part = " ";
|
||||||
|
}
|
||||||
if ( $part =~ /\|$/ ) {
|
if ( $part =~ /\|$/ ) {
|
||||||
|
|
||||||
# this is a cell separator. End the previous cell
|
# this is a cell separator. End the previous cell
|
||||||
|
@ -695,9 +733,9 @@ sub parse {
|
||||||
}
|
}
|
||||||
print STDERR "Starting verse\n" if $debug{parse};
|
print STDERR "Starting verse\n" if $debug{parse};
|
||||||
}
|
}
|
||||||
if ((( $line =~ m/^\[format=(['"]?)(csv|tsv|dsv)\1,/ ) ||
|
if ( ( ( $line =~ m/^\[format=(['"]?)(csv|tsv|dsv)\1,/ ) || ( $line =~ m/^\[separator=[^\|]/ ) )
|
||||||
( $line =~ m/^\[separator=[^\|]/ )) &&
|
&& $self->{options}{'tablecells'} )
|
||||||
$self->{options}{'tablecells'}) {
|
{
|
||||||
warn wrap_mod(
|
warn wrap_mod(
|
||||||
"$ref",
|
"$ref",
|
||||||
dgettext(
|
dgettext(
|
||||||
|
@ -705,7 +743,7 @@ sub parse {
|
||||||
"Po4a's tablecells mode only supports PSV formatted tables with '|' separators. Disabling tablecells and falling back to block mode for this table."
|
"Po4a's tablecells mode only supports PSV formatted tables with '|' separators. Disabling tablecells and falling back to block mode for this table."
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$self->{disabletablecells} = 1;
|
$self->{disabletablecells} = 1;
|
||||||
}
|
}
|
||||||
undef $self->{bullet};
|
undef $self->{bullet};
|
||||||
undef $self->{indent};
|
undef $self->{indent};
|
||||||
|
@ -787,7 +825,7 @@ sub parse {
|
||||||
}
|
}
|
||||||
@comments = ();
|
@comments = ();
|
||||||
} elsif ( not defined $self->{verbatim}
|
} elsif ( not defined $self->{verbatim}
|
||||||
and ( $line =~ m/^([\w\d][\w\d-]*)(::)(\S*)\[(.*)\]$/ ) )
|
and ( $line =~ m/^([\w\d][\w\d-]*)(::)(\S*|\S*\{.*\}\S*)\[(.*)\]$/ ) )
|
||||||
{
|
{
|
||||||
my $macroname = $1;
|
my $macroname = $1;
|
||||||
my $macrotype = $2;
|
my $macrotype = $2;
|
||||||
|
@ -852,7 +890,7 @@ sub parse {
|
||||||
$self->{indent} = $indent;
|
$self->{indent} = $indent;
|
||||||
$self->{bullet} = $bullet;
|
$self->{bullet} = $bullet;
|
||||||
} elsif ( not defined $self->{verbatim}
|
} elsif ( not defined $self->{verbatim}
|
||||||
and ( $line =~ m/^((?:<?[0-9]+)?> +)(.*)$/ ) )
|
and ( $line =~ m/^((?:<?(?:[0-9]|\.)+)?> +)(.*)$/ ) )
|
||||||
{
|
{
|
||||||
my $bullet = $1;
|
my $bullet = $1;
|
||||||
my $text = $2;
|
my $text = $2;
|
||||||
|
@ -966,8 +1004,9 @@ sub parse {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
# End the Table
|
# End the Table
|
||||||
if ( $self->{options}{'tablecells'} and
|
if ( $self->{options}{'tablecells'}
|
||||||
not defined $self->{disabletablecells} ) {
|
and not defined $self->{disabletablecells} )
|
||||||
|
{
|
||||||
do_stripped_unwrapped_paragraph( $self, $paragraph, $wrapped_mode );
|
do_stripped_unwrapped_paragraph( $self, $paragraph, $wrapped_mode );
|
||||||
$self->pushline("\n");
|
$self->pushline("\n");
|
||||||
} else {
|
} else {
|
||||||
|
@ -975,7 +1014,7 @@ sub parse {
|
||||||
}
|
}
|
||||||
undef $self->{verbatim};
|
undef $self->{verbatim};
|
||||||
undef $self->{type};
|
undef $self->{type};
|
||||||
undef $self->{disabletablecells};
|
undef $self->{disabletablecells};
|
||||||
$paragraph = "";
|
$paragraph = "";
|
||||||
}
|
}
|
||||||
$self->pushline( $line . "\n" );
|
$self->pushline( $line . "\n" );
|
||||||
|
@ -996,21 +1035,21 @@ sub parse {
|
||||||
$wrapped_mode = 0;
|
$wrapped_mode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( $paragraph ne "" && $self->{bullet} && length( $self->{indent} || "" ) == 0 )
|
if ( ( $paragraph ne "" && $self->{bullet} && length( $self->{indent} || "" ) == 0 ) )
|
||||||
&& ( !$self->{options}{'nolinting'} ) )
|
|
||||||
{
|
{
|
||||||
|
if ( !$self->{options}{'nolinting'} ) {
|
||||||
# Second line of an item block is not indented. It is unindented
|
# Second line of an item block is not indented. It is unindented
|
||||||
# (and allowed) additional text or a new list item.
|
# (and allowed) additional text or a new list item.
|
||||||
warn wrap_mod(
|
warn wrap_mod(
|
||||||
"$ref",
|
"$ref",
|
||||||
dgettext(
|
dgettext(
|
||||||
"po4a",
|
"po4a",
|
||||||
"It seems that you are adding unindented content to an item. "
|
"It seems that you are adding unindented content to an item. "
|
||||||
. "The standard allows this, but you may still want to change your document "
|
. "The standard allows this, but you may still want to change your document "
|
||||||
. "to use indented text to provide better visual clues to writers."
|
. "to use indented text to provide better visual clues to writers."
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
undef $self->{bullet};
|
undef $self->{bullet};
|
||||||
undef $self->{indent};
|
undef $self->{indent};
|
||||||
|
@ -1056,7 +1095,7 @@ sub do_paragraph {
|
||||||
# }
|
# }
|
||||||
# $type .= " verbatim: '".($self->{verbatim}||"NONE")."' bullet: '$b' indent: '".($self->{indent}||"NONE")."' type: '".($self->{type}||"NONE")."'";
|
# $type .= " verbatim: '".($self->{verbatim}||"NONE")."' bullet: '$b' indent: '".($self->{indent}||"NONE")."' type: '".($self->{type}||"NONE")."'";
|
||||||
|
|
||||||
if ( not $wrap and not defined $self->{verbatim} ) {
|
if ( not defined $self->{verbatim} ) {
|
||||||
|
|
||||||
# Detect bullets
|
# Detect bullets
|
||||||
# | * blah blah
|
# | * blah blah
|
||||||
|
@ -1121,8 +1160,10 @@ sub do_paragraph {
|
||||||
"comment" => join( "\n", @comments ),
|
"comment" => join( "\n", @comments ),
|
||||||
"wrap" => $wrap
|
"wrap" => $wrap
|
||||||
);
|
);
|
||||||
|
my $bullet = $self->{bullet} || "";
|
||||||
|
# print STDERR "translated: '$t', $bullet\n";
|
||||||
|
|
||||||
my $unwrap_result = !$self->{options}{'forcewrap'} && $wrap;
|
my $unwrap_result = !$self->{options}{'forcewrap'} && $wrap && (! ($t =~ /\+\n/) ) ;
|
||||||
if ($unwrap_result) {
|
if ($unwrap_result) {
|
||||||
$t =~ s/(\n| )+/ /g;
|
$t =~ s/(\n| )+/ /g;
|
||||||
}
|
}
|
||||||
|
@ -1318,3 +1359,7 @@ Tested successfully on simple AsciiDoc files.
|
||||||
|
|
||||||
This program is free software; you may redistribute it and/or modify it
|
This program is free software; you may redistribute it and/or modify it
|
||||||
under the terms of GPL (see the COPYING file).
|
under the terms of GPL (see the COPYING file).
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
# LocalWords: Charset charset AsciiDoc tablecells po UTF gettext msgid nostrip
|
||||||
|
|
|
@ -107,7 +107,7 @@ sub show_version {
|
||||||
gettext(
|
gettext(
|
||||||
"%s version %s.\n"
|
"%s version %s.\n"
|
||||||
. "Written by Martin Quinson and Denis Barbier.\n\n"
|
. "Written by Martin Quinson and Denis Barbier.\n\n"
|
||||||
. "Copyright © 2002-2021 Software in the Public Interest, Inc.\n"
|
. "Copyright © 2002-2022 Software in the Public Interest, Inc.\n"
|
||||||
. "This is free software; see source code for copying\n"
|
. "This is free software; see source code for copying\n"
|
||||||
. "conditions. There is NO warranty; not even for\n"
|
. "conditions. There is NO warranty; not even for\n"
|
||||||
. "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
. "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||||
|
|
|
@ -139,7 +139,7 @@ sub parse {
|
||||||
This module is loosely inspired from /usr/lib/dpkg/parsechangelog/debian, which is:
|
This module is loosely inspired from /usr/lib/dpkg/parsechangelog/debian, which is:
|
||||||
|
|
||||||
Copyright © 1996 Ian Jackson. This is free software; see the GNU
|
Copyright © 1996 Ian Jackson. This is free software; see the GNU
|
||||||
General Public Licence version 2 or later for copying conditions. There
|
General Public License version 2 or later for copying conditions. There
|
||||||
is NO warranty.
|
is NO warranty.
|
||||||
|
|
||||||
The adaptation for po4a was done by:
|
The adaptation for po4a was done by:
|
||||||
|
|
|
@ -119,7 +119,7 @@ Increase verbosity.
|
||||||
|
|
||||||
=item B<groff_code>
|
=item B<groff_code>
|
||||||
|
|
||||||
This option permits to change the behavior of the module when it encounter
|
This option controls the behavior of the module when it encounter
|
||||||
a .de, .ie or .if section. It can take the following values:
|
a .de, .ie or .if section. It can take the following values:
|
||||||
|
|
||||||
=over
|
=over
|
||||||
|
@ -148,8 +148,8 @@ should be preferred.
|
||||||
|
|
||||||
This option specifies that the file was generated, and that po4a should not
|
This option specifies that the file was generated, and that po4a should not
|
||||||
try to detect if the man pages was generated from another format.
|
try to detect if the man pages was generated from another format.
|
||||||
This permits to use po4a on generated man pages.
|
This option is mandatory to use po4a on generated man pages.
|
||||||
This option does not take any argument.
|
Note that translating generated pages instead of sources ones is often more fragile, and thus a bad idea.
|
||||||
|
|
||||||
=item B<mdoc>
|
=item B<mdoc>
|
||||||
|
|
||||||
|
@ -173,8 +173,8 @@ This mdoc issue can also be solved with an addendum like this one:
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
The following options permit to specify the behavior of a new macro
|
The following options specify the behavior of a user-defined macro
|
||||||
(defined with a .de request), or of a macro not supported by po4a.
|
(with a .de request), or of a classical macro that is not supported by po4a.
|
||||||
They take as argument a comma-separated list of macros.
|
They take as argument a comma-separated list of macros.
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ I<begin> command; any ending command stop the no_wrap mode.
|
||||||
If you have a I<begin> (respectively I<end>) macro that has no I<end>
|
If you have a I<begin> (respectively I<end>) macro that has no I<end>
|
||||||
(respectively I<begin>), you can specify an existing I<end> (like fi) or
|
(respectively I<begin>), you can specify an existing I<end> (like fi) or
|
||||||
I<begin> (like nf) as a counterpart.
|
I<begin> (like nf) as a counterpart.
|
||||||
These macros (and their arguments) wont be translated.
|
These macros (and their arguments) won't be translated.
|
||||||
|
|
||||||
=item B<inline>
|
=item B<inline>
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ L<po4a(7)|po4a.7>
|
||||||
=head1 AUTHORS
|
=head1 AUTHORS
|
||||||
|
|
||||||
Denis Barbier <barbier@linuxfr.org>
|
Denis Barbier <barbier@linuxfr.org>
|
||||||
Nicolas Francois <nicolas.francois@centraliens.net>
|
Nicolas François <nicolas.francois@centraliens.net>
|
||||||
Martin Quinson (mquinson#debian.org)
|
Martin Quinson (mquinson#debian.org)
|
||||||
|
|
||||||
=head1 COPYRIGHT AND LICENSE
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
@ -1036,15 +1036,14 @@ sub pre_trans {
|
||||||
|
|
||||||
$str =~ s/>/E<gt>/sg;
|
$str =~ s/>/E<gt>/sg;
|
||||||
$str =~ s/</E<lt>/sg;
|
$str =~ s/</E<lt>/sg;
|
||||||
$str =~ s/EE<lt>gt>/E<gt>/g; # could be done in a smarter way?
|
$str =~ s/EE<lt>gt>/E<gt>/g; # could be done in a smarter way?
|
||||||
|
|
||||||
while ( $str =~ m/^(.*)PO4A-INLINE:(.*?):PO4A-INLINE(.*)$/s ) {
|
while ( $str =~ m/^(.*)PO4A-INLINE:(.*?):PO4A-INLINE(.*)$/s ) {
|
||||||
my ( $t1, $t2, $t3 ) = ( $1, $2, $3 );
|
my ( $t1, $t2, $t3 ) = ( $1, $2, $3 );
|
||||||
$str = "$1E<$2>";
|
$str = "$1E<$2>";
|
||||||
if ($mdoc_mode) {
|
if ($mdoc_mode) {
|
||||||
|
|
||||||
# When a punctuation sign must be joined to an argument, mdoc
|
# When a punctuation sign must be joined to an argument, mdoc allows such a construct:
|
||||||
# permits to use such a construct:
|
|
||||||
# .Ar file1 , file2 , file3 ) .
|
# .Ar file1 , file2 , file3 ) .
|
||||||
# Here, we move the punctuation out of the E<...> tag.
|
# Here, we move the punctuation out of the E<...> tag.
|
||||||
# This is reverted in post_trans.
|
# This is reverted in post_trans.
|
||||||
|
@ -1202,7 +1201,12 @@ sub post_trans {
|
||||||
} elsif ( $first eq '>' ) {
|
} elsif ( $first eq '>' ) {
|
||||||
$lvl--;
|
$lvl--;
|
||||||
}
|
}
|
||||||
$done .= $first if ( $lvl > 0 );
|
if ($first eq "\n") {
|
||||||
|
# Don't accept \n within B<> parameters as troff seems to reset font on new line (Debian's #1016753)
|
||||||
|
$done .= ' ' if ( $lvl > 0);
|
||||||
|
} else {
|
||||||
|
$done .= $first if ( $lvl > 0);
|
||||||
|
}
|
||||||
$rest = substr( $rest, 1 );
|
$rest = substr( $rest, 1 );
|
||||||
}
|
}
|
||||||
die wrap_ref_mod( $ref || $self->{ref},
|
die wrap_ref_mod( $ref || $self->{ref},
|
||||||
|
@ -2192,14 +2196,78 @@ $macro{'bp'} = \&untranslated;
|
||||||
# .ad c Start line adjustment in mode c (c=l,r,b,n).
|
# .ad c Start line adjustment in mode c (c=l,r,b,n).
|
||||||
$macro{'ad'} = \&untranslated;
|
$macro{'ad'} = \&untranslated;
|
||||||
|
|
||||||
# .de macro Define or redefine macro until .. is encountered.
|
my %ds_variables;
|
||||||
$macro{'de'} = sub {
|
|
||||||
|
# .ds stringvar anything
|
||||||
|
# Set stringvar to anything.
|
||||||
|
$macro{'ds'} = sub {
|
||||||
|
my ( $self, $m ) = ( shift, shift );
|
||||||
|
my $name = shift;
|
||||||
|
my $string = "@_";
|
||||||
|
$ds_variables{$name} = $string;
|
||||||
|
|
||||||
|
# indicate to which variable this corresponds. The translator can
|
||||||
|
# find references to this string in the translation "\*(name" or
|
||||||
|
# "\*[name]"
|
||||||
|
$self->{type} = "ds $name";
|
||||||
|
$self->pushline( $m . " " . $self->r($name) . " " . $self->translate($string) . "\n" );
|
||||||
|
};
|
||||||
|
|
||||||
|
# .de macro [end] Define or redefine macro until end is encountered (end=.. by default).
|
||||||
|
# .de1 macro [end] Define or redefine macro until end is encountered (end=.. by default), turns off compatibility mode while executing the macro.
|
||||||
|
# .dei macro [end] Define or redefine macro until end is encountered (end=.. by default) substituting parameters with '.ds' content
|
||||||
|
# .dei1 macro [end] Define or redefine macro until end is encountered (end=.. by default) substituting parameters and turning compatibility off
|
||||||
|
|
||||||
|
$macro{'de'} = $macro{'de1'} = $macro{'dei'} = $macro{'dei1'} = sub {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
if ( $groff_code ne "fail" ) {
|
if ( $groff_code ne "fail" ) {
|
||||||
my $paragraph = "@_";
|
my $paragraph = "@_";
|
||||||
my $end = ".";
|
my $end = ".";
|
||||||
if ( $paragraph =~ /^[.'][\t ]*de[\t ]+([^\t ]+)[\t ]+([^\t ]+)[\t ]$/ ) {
|
my $comment;
|
||||||
|
my $macroname = $_[1];
|
||||||
|
$macroname = $ds_variables{$macroname} if ( $_[0] eq "dei" || $_[0] eq "dei1" );
|
||||||
|
if ($macroname =~ m/(.*?)\\"(.*)$/) {
|
||||||
|
# Remove comments after the macro name (Debian's #1017837)
|
||||||
|
($macroname, $comment) = ($1, $2);
|
||||||
|
}
|
||||||
|
$macroname =~ s/^ *//;
|
||||||
|
$macroname =~ s/ *$//;
|
||||||
|
unless (exists $macro{$macroname} || exists $inline{$macroname}) {
|
||||||
|
if (defined $comment) {
|
||||||
|
$comment =~ s/^ *//;
|
||||||
|
$comment =~ s/ *$//;
|
||||||
|
warn wrap_mod(
|
||||||
|
"po4a::man",
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"This page defines a new macro '%s' with '%s' (inline comment: %s), but you did not specify the expected po4a behavior "
|
||||||
|
. "when '%s' is used. You will get an error if this macro is actually used in your page.\n"
|
||||||
|
. "Add your macro to one of the '%s', '%s', '%s', '%s', '%s' or '%s' parameters to avoid issues.\n"
|
||||||
|
. "For example, passing '%s' to po4a will ensure that the defined macro remains hidden from translators.\n"
|
||||||
|
. "Please refer to the manpage of Locale::Po4a::Man for more info on these parameters.\n"
|
||||||
|
),
|
||||||
|
$macroname, $_[0], $comment, $macroname,
|
||||||
|
'untranslated', 'noarg', 'translate_joined', 'translate_each', 'no_wrap', 'inline', "-o untranslated=$macroname");
|
||||||
|
} else {
|
||||||
|
warn wrap_mod(
|
||||||
|
"po4a::man",
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"This page defines a new macro '%s' with '%s', but you did not specify the expected po4a behavior "
|
||||||
|
. "when '%s' is used. You will get an error if this macro is actually used in your page.\n"
|
||||||
|
. "Add your macro to one of the '%s', '%s', '%s', '%s', '%s' or '%s' parameters to avoid issues.\n"
|
||||||
|
. "For example, passing '%s' to po4a will ensure that the defined macro remains hidden from translators.\n"
|
||||||
|
. "Please refer to the manpage of Locale::Po4a::Man for more info on these parameters.\n"
|
||||||
|
),
|
||||||
|
$macroname,
|
||||||
|
$_[0],$macroname,
|
||||||
|
'untranslated', 'noarg', 'translate_joined', 'translate_each', 'no_wrap', 'inline', "-o untranslated=$macroname"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( $paragraph =~ /^[.'][\t ]*d[ei1]*[\t ]+([^\t ]+)[\t ]+([^\t ]+)[\t ]$/ ) {
|
||||||
$end = $2;
|
$end = $2;
|
||||||
|
$end = $ds_variables{$end} if ( $_[0] eq "dei" || $_[0] eq "dei1" );
|
||||||
}
|
}
|
||||||
my ( $line, $ref ) = $self->SUPER::shiftline();
|
my ( $line, $ref ) = $self->SUPER::shiftline();
|
||||||
chomp $line;
|
chomp $line;
|
||||||
|
@ -2223,26 +2291,17 @@ $macro{'de'} = sub {
|
||||||
"po4a::man",
|
"po4a::man",
|
||||||
dgettext(
|
dgettext(
|
||||||
"po4a",
|
"po4a",
|
||||||
"This page defines a new macro with '.de'. Since po4a is not a real groff parser, this is not supported."
|
"This page defines a new macro with '%s'. Since po4a is not a real groff parser, this is not supported. "
|
||||||
)
|
. "The option '%s' gets these macros copied verbatim in the translated file, but it's not very robust. "
|
||||||
|
. "'%s' shows these macros to the translators, but groff macros are not user-friendly for translators."
|
||||||
|
),
|
||||||
|
$_[0],
|
||||||
|
"groff_code=verbatim",
|
||||||
|
"groff_code=translate"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
# .ds stringvar anything
|
|
||||||
# Set stringvar to anything.
|
|
||||||
$macro{'ds'} = sub {
|
|
||||||
my ( $self, $m ) = ( shift, shift );
|
|
||||||
my $name = shift;
|
|
||||||
my $string = "@_";
|
|
||||||
|
|
||||||
# indicate to which variable this corresponds. The translator can
|
|
||||||
# find references to this string in the translation "\*(name" or
|
|
||||||
# "\*[name]"
|
|
||||||
$self->{type} = "ds $name";
|
|
||||||
$self->pushline( $m . " " . $self->r($name) . " " . $self->translate($string) . "\n" );
|
|
||||||
};
|
|
||||||
|
|
||||||
# .fam Return to previous font family.
|
# .fam Return to previous font family.
|
||||||
# .fam name Set the current font family to name.
|
# .fam name Set the current font family to name.
|
||||||
$macro{'fam'} = \&untranslated;
|
$macro{'fam'} = \&untranslated;
|
||||||
|
@ -2328,13 +2387,20 @@ $macro{'ie'} = $macro{'if'} = sub {
|
||||||
"po4a::man",
|
"po4a::man",
|
||||||
dgettext(
|
dgettext(
|
||||||
"po4a",
|
"po4a",
|
||||||
"This page uses conditionals with '%s'. Since po4a is not a real groff parser, this is not supported."
|
"This page uses conditionals with '%s'. Since po4a is not a real groff parser, this is not supported by default. "
|
||||||
|
. "The option '%s' gets these macros copied verbatim in the translated file, but it's not very robust. "
|
||||||
|
. "'%s' shows these macros to the translators, but groff macros are not user-friendly for translators."
|
||||||
),
|
),
|
||||||
$_[0]
|
$_[0],
|
||||||
|
"groff_code=verbatim",
|
||||||
|
"groff_code=translate"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# .el anything Display the parameter (part of a if-then-else with .ie)
|
||||||
|
$macro{'el'} = \&translate_joined;
|
||||||
|
|
||||||
# .in N Change indent according to N (default scaling indicator m).
|
# .in N Change indent according to N (default scaling indicator m).
|
||||||
$macro{'in'} = \&untranslated;
|
$macro{'in'} = \&untranslated;
|
||||||
|
|
||||||
|
@ -2352,6 +2418,9 @@ $macro{'ig'} = sub {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# .it n macro Set an input line trap.
|
||||||
|
$macro{'it'} = \&untranslated;
|
||||||
|
|
||||||
# .lf N file Set input line number to N and filename to file.
|
# .lf N file Set input line number to N and filename to file.
|
||||||
$macro{'lf'} = \&untranslated;
|
$macro{'lf'} = \&untranslated;
|
||||||
|
|
||||||
|
@ -2417,9 +2486,9 @@ $macro{'ti'} = \&untranslated;
|
||||||
###
|
###
|
||||||
$macro{'TS'} = sub {
|
$macro{'TS'} = sub {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ( $in_headers, $tab, $buffer ) = ( 1, "\t", "" );
|
my ( $in_headers, $tab, $buffer ) = ( 1, "\t", "" );
|
||||||
my ( $in_textblock, $preline, $postline ) = ( 0, "", "" );
|
my ( $in_textblock, $preline, $postline ) = ( 0, "", "" );
|
||||||
my ( $line, $ref ) = $self->shiftline();
|
my ( $line, $ref ) = $self->shiftline();
|
||||||
my @options;
|
my @options;
|
||||||
|
|
||||||
# Push table start
|
# Push table start
|
||||||
|
@ -2801,3 +2870,7 @@ sub define_mdoc_macros {
|
||||||
$macro{'br'} = \&noarg;
|
$macro{'br'} = \&noarg;
|
||||||
|
|
||||||
} # end of define_mdoc_macros
|
} # end of define_mdoc_macros
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
# LocalWords: Charset charset po UTF gettext msgid nostrip
|
||||||
|
|
|
@ -265,6 +265,9 @@ sub initialize {
|
||||||
# count_doc: number of strings in the document
|
# count_doc: number of strings in the document
|
||||||
# (duplicate strings counted multiple times)
|
# (duplicate strings counted multiple times)
|
||||||
$self->{count_doc} = 0;
|
$self->{count_doc} = 0;
|
||||||
|
$self->{gettextize_types} = (); # Type of each msgid found in the doc, in order
|
||||||
|
# We cannot use {$msgid}{'type'} as a type because for duplicate entries, the type is overwritten.
|
||||||
|
# So we have to copy the same info to this separate array, which is accessed through type_doc()
|
||||||
$self->{header_comment} =
|
$self->{header_comment} =
|
||||||
" SOME DESCRIPTIVE TITLE\n"
|
" SOME DESCRIPTIVE TITLE\n"
|
||||||
. " Copyright (C) YEAR "
|
. " Copyright (C) YEAR "
|
||||||
|
@ -646,7 +649,7 @@ sub write_if_needed {
|
||||||
my $basename = basename($filename);
|
my $basename = basename($filename);
|
||||||
( undef, $tmp_filename ) = File::Temp::tempfile(
|
( undef, $tmp_filename ) = File::Temp::tempfile(
|
||||||
$basename . "XXXX",
|
$basename . "XXXX",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
OPEN => 0,
|
OPEN => 0,
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
);
|
);
|
||||||
|
@ -657,169 +660,6 @@ sub write_if_needed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
=item gettextize($$)
|
|
||||||
|
|
||||||
This function produces one translated message catalog from two catalogs, an
|
|
||||||
original and a translation. This process is described in L<po4a(7)|po4a.7>,
|
|
||||||
section I<Gettextization: how does it work?>.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub gettextize {
|
|
||||||
my $this = shift;
|
|
||||||
my $class = ref($this) || $this;
|
|
||||||
my ( $poorig, $potrans ) = ( shift, shift );
|
|
||||||
|
|
||||||
my $pores = Locale::Po4a::Po->new();
|
|
||||||
|
|
||||||
my $please_fail = 0;
|
|
||||||
my $toobad = dgettext( "po4a",
|
|
||||||
"\nThe gettextization failed (once again). Don't give up, "
|
|
||||||
. "gettextizing is a subtle art, but this is only needed once "
|
|
||||||
. "to convert a project to the gorgeous luxus offered by po4a "
|
|
||||||
. "to translators."
|
|
||||||
. "\nPlease refer to the po4a(7) documentation, the section "
|
|
||||||
. "\"HOWTO convert a pre-existing translation to po4a?\" "
|
|
||||||
. "contains several hints to help you in your task" );
|
|
||||||
|
|
||||||
# Don't fail right now when the entry count does not match. Instead, give
|
|
||||||
# it a try so that the user can see where we fail (which is probably where
|
|
||||||
# the problem is).
|
|
||||||
if ( $poorig->count_entries_doc() > $potrans->count_entries_doc() ) {
|
|
||||||
warn wrap_mod(
|
|
||||||
"po4a gettextize",
|
|
||||||
dgettext(
|
|
||||||
"po4a",
|
|
||||||
"Original has more strings than the translation (%d>%d). "
|
|
||||||
. "Please fix it by editing the translated version to add "
|
|
||||||
. "some dummy entry."
|
|
||||||
),
|
|
||||||
$poorig->count_entries_doc(),
|
|
||||||
$potrans->count_entries_doc()
|
|
||||||
);
|
|
||||||
$please_fail = 1;
|
|
||||||
} elsif ( $poorig->count_entries_doc() < $potrans->count_entries_doc() ) {
|
|
||||||
warn wrap_mod(
|
|
||||||
"po4a gettextize",
|
|
||||||
dgettext(
|
|
||||||
"po4a",
|
|
||||||
"Original has less strings than the translation (%d<%d). "
|
|
||||||
. "Please fix it by removing the extra entry from the "
|
|
||||||
. "translated file. You may need an addendum (cf po4a(7)) "
|
|
||||||
. "to reput the chunk in place after gettextization. A "
|
|
||||||
. "possible cause is that a text duplicated in the original "
|
|
||||||
. "is not translated the same way each time. Remove one of "
|
|
||||||
. "the translations, and you're fine."
|
|
||||||
),
|
|
||||||
$poorig->count_entries_doc(),
|
|
||||||
$potrans->count_entries_doc()
|
|
||||||
);
|
|
||||||
$please_fail = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $poorig->get_charset =~ /^utf-8$/i ) {
|
|
||||||
$potrans->to_utf8;
|
|
||||||
$pores->set_charset("UTF-8");
|
|
||||||
} else {
|
|
||||||
my $charset = $potrans->get_charset();
|
|
||||||
$charset = "UTF-8" if $charset eq "CHARSET";
|
|
||||||
$pores->set_charset($charset);
|
|
||||||
}
|
|
||||||
print "Po character sets:\n"
|
|
||||||
. " original="
|
|
||||||
. $poorig->get_charset . "\n"
|
|
||||||
. " translated="
|
|
||||||
. $potrans->get_charset . "\n"
|
|
||||||
. " result="
|
|
||||||
. $pores->get_charset . "\n"
|
|
||||||
if $debug{'encoding'};
|
|
||||||
|
|
||||||
for (
|
|
||||||
my ( $o, $t ) = ( 0, 0 ) ;
|
|
||||||
$o < $poorig->count_entries_doc() && $t < $potrans->count_entries_doc() ;
|
|
||||||
$o++, $t++
|
|
||||||
)
|
|
||||||
{
|
|
||||||
#
|
|
||||||
# Extract some informations
|
|
||||||
|
|
||||||
my ( $orig, $trans ) = ( $poorig->msgid_doc($o), $potrans->msgid_doc($t) );
|
|
||||||
|
|
||||||
# print STDERR "Matches [[$orig]]<<$trans>>\n";
|
|
||||||
|
|
||||||
my ( $reforig, $reftrans ) = ( $poorig->{po}{$orig}{'reference'}, $potrans->{po}{$trans}{'reference'} );
|
|
||||||
my ( $typeorig, $typetrans ) = ( $poorig->{po}{$orig}{'type'}, $potrans->{po}{$trans}{'type'} );
|
|
||||||
|
|
||||||
#
|
|
||||||
# Make sure the type of both string exist
|
|
||||||
#
|
|
||||||
die wrap_mod( "po4a gettextize", "Internal error: type of original string number %s " . "isn't provided", $o )
|
|
||||||
if ( $typeorig eq '' );
|
|
||||||
|
|
||||||
die wrap_mod( "po4a gettextize", "Internal error: type of translated string number %s " . "isn't provided", $o )
|
|
||||||
if ( $typetrans eq '' );
|
|
||||||
|
|
||||||
#
|
|
||||||
# Make sure both type are the same
|
|
||||||
#
|
|
||||||
if ( $typeorig ne $typetrans ) {
|
|
||||||
$pores->write("gettextization.failed.po");
|
|
||||||
eval {
|
|
||||||
# Recode $trans into current charset, if possible
|
|
||||||
require I18N::Langinfo;
|
|
||||||
I18N::Langinfo->import(qw(langinfo CODESET));
|
|
||||||
my $codeset = langinfo( CODESET() );
|
|
||||||
Encode::from_to( $trans, $potrans->get_charset, $codeset );
|
|
||||||
};
|
|
||||||
die wrap_msg(
|
|
||||||
dgettext( "po4a",
|
|
||||||
"po4a gettextization: Structure disparity between "
|
|
||||||
. "original and translated files:\n"
|
|
||||||
. "msgid (at %s) is of type '%s' while\n"
|
|
||||||
. "msgstr (at %s) is of type '%s'.\n"
|
|
||||||
. "Original text: %s\n"
|
|
||||||
. "Translated text: %s\n"
|
|
||||||
. "(result so far dumped to gettextization.failed.po)" )
|
|
||||||
. "%s",
|
|
||||||
$reforig,
|
|
||||||
$typeorig,
|
|
||||||
$reftrans,
|
|
||||||
$typetrans,
|
|
||||||
$orig, $trans, $toobad
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Push the entry
|
|
||||||
#
|
|
||||||
my $flags;
|
|
||||||
if ( defined $poorig->{po}{$orig}{'flags'} ) {
|
|
||||||
$flags = $poorig->{po}{$orig}{'flags'} . " fuzzy";
|
|
||||||
} else {
|
|
||||||
$flags = "fuzzy";
|
|
||||||
}
|
|
||||||
$pores->push_raw(
|
|
||||||
'msgid' => $orig,
|
|
||||||
'msgstr' => $trans,
|
|
||||||
'flags' => $flags,
|
|
||||||
'type' => $typeorig,
|
|
||||||
'reference' => $reforig,
|
|
||||||
'conflict' => 1,
|
|
||||||
'transref' => $potrans->{po}{$trans}{'reference'}
|
|
||||||
)
|
|
||||||
unless ( defined( $pores->{po}{$orig} )
|
|
||||||
and ( $pores->{po}{$orig}{'msgstr'} eq $trans ) )
|
|
||||||
|
|
||||||
# FIXME: maybe we should be smarter about what reference should be
|
|
||||||
# sent to push_raw.
|
|
||||||
}
|
|
||||||
|
|
||||||
# make sure we return a useful error message when entry count differ
|
|
||||||
die "$toobad\n" if $please_fail;
|
|
||||||
|
|
||||||
return $pores;
|
|
||||||
}
|
|
||||||
|
|
||||||
=item filter($)
|
=item filter($)
|
||||||
|
|
||||||
This function extracts a catalog from an existing one. Only the entries having
|
This function extracts a catalog from an existing one. Only the entries having
|
||||||
|
@ -1401,14 +1241,15 @@ sub push_raw {
|
||||||
|
|
||||||
if ($keep_conflict) {
|
if ($keep_conflict) {
|
||||||
if ( $self->{po}{$msgid}{'msgstr'} =~ m/^#-#-#-#-# .* #-#-#-#-#\\n/s ) {
|
if ( $self->{po}{$msgid}{'msgstr'} =~ m/^#-#-#-#-# .* #-#-#-#-#\\n/s ) {
|
||||||
$msgstr = $self->{po}{$msgid}{'msgstr'} . "\\n#-#-#-#-# $transref #-#-#-#-#\\n" . $msgstr;
|
$msgstr = $self->{po}{$msgid}{'msgstr'} . "\\n#-#-#-#-# $transref (type: $type) #-#-#-#-#\\n" . $msgstr;
|
||||||
} else {
|
} else {
|
||||||
$msgstr =
|
$msgstr =
|
||||||
"#-#-#-#-# "
|
"#-#-#-#-# "
|
||||||
. $self->{po}{$msgid}{'transref'}
|
. $self->{po}{$msgid}{'transref'}
|
||||||
. " #-#-#-#-#\\n"
|
. " (type " . $self->{po}{$msgid}{'type'}
|
||||||
|
. ") #-#-#-#-#\\n"
|
||||||
. $self->{po}{$msgid}{'msgstr'} . "\\n"
|
. $self->{po}{$msgid}{'msgstr'} . "\\n"
|
||||||
. "#-#-#-#-# $transref #-#-#-#-#\\n"
|
. "#-#-#-#-# $transref (type: $type) #-#-#-#-#\\n"
|
||||||
. $msgstr;
|
. $msgstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1451,11 +1292,11 @@ sub push_raw {
|
||||||
$self->{po}{$msgid}{'comment'} = $comment;
|
$self->{po}{$msgid}{'comment'} = $comment;
|
||||||
$self->{po}{$msgid}{'automatic'} = $automatic;
|
$self->{po}{$msgid}{'automatic'} = $automatic;
|
||||||
$self->{po}{$msgid}{'previous'} = $previous;
|
$self->{po}{$msgid}{'previous'} = $previous;
|
||||||
if ( defined( $self->{po}{$msgid}{'pos_doc'} ) ) {
|
|
||||||
$self->{po}{$msgid}{'pos_doc'} .= " " . $self->{count_doc}++;
|
$self->{po}{$msgid}{pos_doc} = () unless (defined( $self->{po}{$msgid}{pos_doc}));
|
||||||
} else {
|
CORE::push( @{ $self->{po}{$msgid}{pos_doc} }, $self->{count_doc}++);
|
||||||
$self->{po}{$msgid}{'pos_doc'} = $self->{count_doc}++;
|
CORE::push( @{ $self->{gettextize_types} }, $type);
|
||||||
}
|
|
||||||
unless ( defined( $self->{po}{$msgid}{'pos'} ) ) {
|
unless ( defined( $self->{po}{$msgid}{'pos'} ) ) {
|
||||||
$self->{po}{$msgid}{'pos'} = $self->{count}++;
|
$self->{po}{$msgid}{'pos'} = $self->{count}++;
|
||||||
}
|
}
|
||||||
|
@ -1515,37 +1356,6 @@ sub count_entries_doc($) {
|
||||||
return $self->{count_doc};
|
return $self->{count_doc};
|
||||||
}
|
}
|
||||||
|
|
||||||
=item equals_msgid(po)
|
|
||||||
|
|
||||||
Returns ($uptodate, $diagnostic) with $uptodate indicating whether all msgid of the current po file are
|
|
||||||
also present in the one passed as parameter (all other fields are ignored in the file comparison).
|
|
||||||
Informally, if $uptodate returns false, then the po files would be changed when going through B<po4a-updatepo>.
|
|
||||||
|
|
||||||
If $uptodate is false, then $diagnostic contains a diagnostic of why this is so.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub equals_msgid($$) {
|
|
||||||
my ( $self, $other ) = ( shift, shift );
|
|
||||||
|
|
||||||
unless ( $self->count_entries() == $other->count_entries() ) {
|
|
||||||
return (
|
|
||||||
0,
|
|
||||||
wrap_msg(
|
|
||||||
dgettext( "po4a", "The amount of entries differ between files: %d is not %d" ),
|
|
||||||
$self->count_entries(),
|
|
||||||
$other->count_entries()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
foreach my $msgid ( keys %{ $self->{po} } ) {
|
|
||||||
unless ( defined( $self->{po}{$msgid} ) && defined( $other->{po}{$msgid} ) ) {
|
|
||||||
return ( 0, wrap_msg( dgettext( "po4a", "msgid declared in one file only: %s\n" ), $msgid ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ( 1, "" );
|
|
||||||
}
|
|
||||||
|
|
||||||
=item msgid($)
|
=item msgid($)
|
||||||
|
|
||||||
Returns the msgid of the given number.
|
Returns the msgid of the given number.
|
||||||
|
@ -1573,13 +1383,29 @@ sub msgid_doc($$) {
|
||||||
my $num = shift;
|
my $num = shift;
|
||||||
|
|
||||||
foreach my $msgid ( keys %{ $self->{po} } ) {
|
foreach my $msgid ( keys %{ $self->{po} } ) {
|
||||||
foreach my $pos ( split / /, $self->{po}{$msgid}{'pos_doc'} ) {
|
foreach my $pos ( @{ $self->{po}{$msgid}{'pos_doc'} } ) {
|
||||||
return $msgid if ( $pos eq $num );
|
return $msgid if ( $pos eq $num );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=item type_doc($)
|
||||||
|
|
||||||
|
Returns the type of the msgid with the given position in the document. This is
|
||||||
|
probably only useful to gettextization, and it's stored separately from
|
||||||
|
{$msgid}{'type'} because the later location may be overwritten by another type
|
||||||
|
when the $msgid is duplicated in the master document.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub type_doc($$) {
|
||||||
|
my $self = shift;
|
||||||
|
my $num = shift;
|
||||||
|
|
||||||
|
return ${ $self->{gettextize_types} }[$num];
|
||||||
|
}
|
||||||
|
|
||||||
=item get_charset()
|
=item get_charset()
|
||||||
|
|
||||||
Returns the character set specified in the PO header. If it hasn't been
|
Returns the character set specified in the PO header. If it hasn't been
|
||||||
|
@ -1689,7 +1515,7 @@ sub escape_text {
|
||||||
# on the 80th char, but without changing the meaning of the string)
|
# on the 80th char, but without changing the meaning of the string)
|
||||||
sub quote_text {
|
sub quote_text {
|
||||||
my $string = shift;
|
my $string = shift;
|
||||||
my $do_wrap = shift; # either 'no' or 'newlines', or column at which we should wrap
|
my $do_wrap = shift // 'no'; # either 'no' or 'newlines', or column at which we should wrap
|
||||||
|
|
||||||
return '""' unless length($string);
|
return '""' unless length($string);
|
||||||
|
|
||||||
|
|
|
@ -399,7 +399,7 @@ sub parse_file {
|
||||||
my ( $tmpfh, $tmpfile ) = File::Temp::tempfile(
|
my ( $tmpfh, $tmpfile ) = File::Temp::tempfile(
|
||||||
"po4a-XXXX",
|
"po4a-XXXX",
|
||||||
SUFFIX => ".sgml",
|
SUFFIX => ".sgml",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
);
|
);
|
||||||
print $tmpfh $origfile;
|
print $tmpfh $origfile;
|
||||||
|
@ -434,7 +434,7 @@ sub parse_file {
|
||||||
# Get the prolog
|
# Get the prolog
|
||||||
{
|
{
|
||||||
$prolog = $origfile;
|
$prolog = $origfile;
|
||||||
my $lvl; # number of '<' seen without matching '>'
|
my $lvl; # number of '<' seen without matching '>'
|
||||||
my $pos = 0; # where in the document (in chars) while detecting prolog boundaries
|
my $pos = 0; # where in the document (in chars) while detecting prolog boundaries
|
||||||
|
|
||||||
unless ( $prolog =~ s/^(.*<!DOCTYPE).*$/$1/is ) {
|
unless ( $prolog =~ s/^(.*<!DOCTYPE).*$/$1/is ) {
|
||||||
|
@ -773,7 +773,7 @@ sub parse_file {
|
||||||
while ( $origfile =~ /^(.*?)&$key(;.*$|[^-_:.A-Za-z0-9].*$|$)/s ) {
|
while ( $origfile =~ /^(.*?)&$key(;.*$|[^-_:.A-Za-z0-9].*$|$)/s ) {
|
||||||
|
|
||||||
# Since we will include a new file, we
|
# Since we will include a new file, we
|
||||||
# must do a new round of substitutions.
|
# must do a new round of substitutions.
|
||||||
$dosubstitution = 1;
|
$dosubstitution = 1;
|
||||||
my ( $begin, $end ) = ( $1, $2 );
|
my ( $begin, $end ) = ( $1, $2 );
|
||||||
$end = "" unless ( defined $end );
|
$end = "" unless ( defined $end );
|
||||||
|
@ -789,7 +789,7 @@ sub parse_file {
|
||||||
# add the refs
|
# add the refs
|
||||||
my $len = $entincl{$key}{'length'}; # number added by the inclusion
|
my $len = $entincl{$key}{'length'}; # number added by the inclusion
|
||||||
my $pre = ( $begin =~ tr/\n/\n/ ); # number of \n
|
my $pre = ( $begin =~ tr/\n/\n/ ); # number of \n
|
||||||
my $post = ( $end =~ tr/\n/\n/ );
|
my $post = ( $end =~ tr/\n/\n/ );
|
||||||
print "XX Add a ref. pre=$pre; len=$len; post=$post\n"
|
print "XX Add a ref. pre=$pre; len=$len; post=$post\n"
|
||||||
if $debug{'refs'};
|
if $debug{'refs'};
|
||||||
|
|
||||||
|
@ -852,7 +852,7 @@ sub parse_file {
|
||||||
my ( $tmpfh, $tmpfile ) = File::Temp::tempfile(
|
my ( $tmpfh, $tmpfile ) = File::Temp::tempfile(
|
||||||
"po4a-XXXX",
|
"po4a-XXXX",
|
||||||
SUFFIX => ".sgml",
|
SUFFIX => ".sgml",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
);
|
);
|
||||||
print $tmpfh $origfile;
|
print $tmpfh $origfile;
|
||||||
|
|
|
@ -166,8 +166,7 @@ this environment does not take any parameters.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
Using these options permits to override the behaviour of the commands defined
|
Use these options to override the default behavior of the defined commands.
|
||||||
in the default lists.
|
|
||||||
|
|
||||||
=head1 INLINE CUSTOMIZATION
|
=head1 INLINE CUSTOMIZATION
|
||||||
|
|
||||||
|
@ -184,7 +183,7 @@ treated as the arguments of the I<command2> command.
|
||||||
|
|
||||||
=item B<% po4a: command> I<command1> I<parameters>
|
=item B<% po4a: command> I<command1> I<parameters>
|
||||||
|
|
||||||
This permit to describe in detail the parameters of the I<command1>
|
This describes in detail the parameters of the I<command1>
|
||||||
command.
|
command.
|
||||||
This information will be used to check the number of arguments and their
|
This information will be used to check the number of arguments and their
|
||||||
types.
|
types.
|
||||||
|
@ -206,7 +205,7 @@ As for an asterisk, the command will be extracted if it appear at an
|
||||||
extremity of a block, but the parameters won't be translated separately.
|
extremity of a block, but the parameters won't be translated separately.
|
||||||
The translator will have to translate the command concatenated to all its
|
The translator will have to translate the command concatenated to all its
|
||||||
parameters.
|
parameters.
|
||||||
This permits to keep more context, and is useful for commands with small
|
This keeps more context, and is useful for commands with small
|
||||||
words in parameter, which can have multiple meanings (and translations).
|
words in parameter, which can have multiple meanings (and translations).
|
||||||
|
|
||||||
Note: In this case you don't have to specify which parameters are
|
Note: In this case you don't have to specify which parameters are
|
||||||
|
@ -244,9 +243,9 @@ command.
|
||||||
|
|
||||||
=item B<% po4a: environment> I<env> I<parameters>
|
=item B<% po4a: environment> I<env> I<parameters>
|
||||||
|
|
||||||
This permits to define the parameters accepted by the I<env> environment.
|
This defines the parameters accepted by the I<env> environment and specifies the ones to be translated.
|
||||||
This information is later used to check the number of arguments of the
|
This information is later used to check the number of arguments of the
|
||||||
\begin command, and permit to specify which one must be translated.
|
\begin command.
|
||||||
The syntax of the I<parameters> argument is the same as described for the
|
The syntax of the I<parameters> argument is the same as described for the
|
||||||
others commands.
|
others commands.
|
||||||
The first parameter of the \begin command is the name of the environment.
|
The first parameter of the \begin command is the name of the environment.
|
||||||
|
@ -264,7 +263,7 @@ Indicates that an environment should be split according to the given
|
||||||
regular expression.
|
regular expression.
|
||||||
|
|
||||||
The regular expression is delimited by quotes.
|
The regular expression is delimited by quotes.
|
||||||
It should not create any backreference.
|
It should not create any back-reference.
|
||||||
You should use (?:) if you need a group.
|
You should use (?:) if you need a group.
|
||||||
It may also need some escapes.
|
It may also need some escapes.
|
||||||
|
|
||||||
|
@ -1121,7 +1120,7 @@ sub parse_definition_line {
|
||||||
}
|
}
|
||||||
} elsif ( $line =~ /^separator\s+(\w+(?:\[#[0-9]+\])?)\s+\"(.*)\"\s*$/ ) {
|
} elsif ( $line =~ /^separator\s+(\w+(?:\[#[0-9]+\])?)\s+\"(.*)\"\s*$/ ) {
|
||||||
my $env = $1; # This is not necessarily an environment.
|
my $env = $1; # This is not necessarily an environment.
|
||||||
# It can also be smth like 'title[#1]'.
|
# It can also be something like 'title[#1]'.
|
||||||
$env_separators{$env} = $2;
|
$env_separators{$env} = $2;
|
||||||
} elsif ( $line =~ /^verbatim\s+environment\s+(\w+)\s+$/ ) {
|
} elsif ( $line =~ /^verbatim\s+environment\s+(\w+)\s+$/ ) {
|
||||||
register_verbatim_environment($1);
|
register_verbatim_environment($1);
|
||||||
|
@ -1721,7 +1720,7 @@ attached to the following string.
|
||||||
=item Some commands should be added to the environment stack
|
=item Some commands should be added to the environment stack
|
||||||
|
|
||||||
These commands should be specified by couples.
|
These commands should be specified by couples.
|
||||||
This could allow to specify commands beginning or ending a verbatim
|
This can be used to specify commands beginning or ending a verbatim
|
||||||
environment.
|
environment.
|
||||||
|
|
||||||
=item Others
|
=item Others
|
||||||
|
@ -1754,3 +1753,7 @@ under the terms of GPL (see the COPYING file).
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
# LocalWords: Charset charset po UTF gettext msgid nostrip LaTeX
|
||||||
|
|
|
@ -58,6 +58,7 @@ use vars qw(@ISA @EXPORT);
|
||||||
use Locale::Po4a::TransTractor;
|
use Locale::Po4a::TransTractor;
|
||||||
use Locale::Po4a::Common;
|
use Locale::Po4a::Common;
|
||||||
use YAML::Tiny;
|
use YAML::Tiny;
|
||||||
|
use Syntax::Keyword::Try;
|
||||||
|
|
||||||
=head1 OPTIONS ACCEPTED BY THIS MODULE
|
=head1 OPTIONS ACCEPTED BY THIS MODULE
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ my $breaks;
|
||||||
=item B<debianchangelog>
|
=item B<debianchangelog>
|
||||||
|
|
||||||
Handle the header and footer of
|
Handle the header and footer of
|
||||||
released versions, which only contain non translatable informations.
|
released versions, which only contain non translatable information.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
@ -148,14 +149,41 @@ my $markdown = 0;
|
||||||
=item B<yfm_keys> (markdown-only)
|
=item B<yfm_keys> (markdown-only)
|
||||||
|
|
||||||
Comma-separated list of keys to process for translation in the YAML Front Matter
|
Comma-separated list of keys to process for translation in the YAML Front Matter
|
||||||
section. All other keys are skipped. Keys are matched with a case-insensitive
|
section. All other keys are skipped. Keys are matched with a case-sensitive
|
||||||
match. Array values are always translated, unless the B<yfm_skip_array> option
|
match. If B<yfm_paths> and B<yfm_keys> are used together, values are included if
|
||||||
is provided.
|
they are matched by at least one of the options. Array values are always translated,
|
||||||
|
unless the B<yfm_skip_array> option is provided.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
my %yfm_keys = ();
|
my %yfm_keys = ();
|
||||||
|
|
||||||
|
=item B<yfm_lenient> (markdown only)
|
||||||
|
|
||||||
|
Allow the YAML Front Matter parser to fail on malformated headers. This is
|
||||||
|
particularly helpful when your file starts with a horizontal ruler instead
|
||||||
|
of a YAML Front Matter, but you insist on using three dashes only for your
|
||||||
|
ruler.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
my $yfm_lenient = 0;
|
||||||
|
|
||||||
|
=item B<yfm_paths> (markdown only)
|
||||||
|
|
||||||
|
=item B<yfm_paths>
|
||||||
|
|
||||||
|
Comma-separated list of hash paths to process for extraction in the YAML
|
||||||
|
Front Matter section, all other paths are skipped. Paths are matched with a
|
||||||
|
case-sensitive match. If B<yfm_paths> and B<yfm_keys> are used together,
|
||||||
|
values are included if they are matched by at least one of the options.
|
||||||
|
Arrays values are always returned unless the B<yfm_skip_array> option is
|
||||||
|
provided.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
my %yfm_paths = ();
|
||||||
|
|
||||||
=item B<yfm_skip_array> (markdown-only)
|
=item B<yfm_skip_array> (markdown-only)
|
||||||
|
|
||||||
Do not translate array values in the YAML Front Matter section.
|
Do not translate array values in the YAML Front Matter section.
|
||||||
|
@ -200,6 +228,8 @@ sub initialize {
|
||||||
$self->{options}{'fortunes'} = 1;
|
$self->{options}{'fortunes'} = 1;
|
||||||
$self->{options}{'markdown'} = 1;
|
$self->{options}{'markdown'} = 1;
|
||||||
$self->{options}{'yfm_keys'} = '';
|
$self->{options}{'yfm_keys'} = '';
|
||||||
|
$self->{options}{'yfm_lenient'} = 0;
|
||||||
|
$self->{options}{'yfm_paths'} = '';
|
||||||
$self->{options}{'yfm_skip_array'} = 0;
|
$self->{options}{'yfm_skip_array'} = 0;
|
||||||
$self->{options}{'nobullets'} = 0;
|
$self->{options}{'nobullets'} = 0;
|
||||||
$self->{options}{'keyvalue'} = 1;
|
$self->{options}{'keyvalue'} = 1;
|
||||||
|
@ -229,11 +259,16 @@ sub initialize {
|
||||||
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||||
$yfm_keys{$_} = 1
|
$yfm_keys{$_} = 1
|
||||||
} ( split( ',', $self->{options}{'yfm_keys'} ) );
|
} ( split( ',', $self->{options}{'yfm_keys'} ) );
|
||||||
|
map {
|
||||||
|
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||||
|
$yfm_paths{$_} = 1
|
||||||
|
} ( split( ',', $self->{options}{'yfm_paths'} ) );
|
||||||
|
|
||||||
# map { print STDERR "key $_\n"; } (keys %yfm_keys);
|
# map { print STDERR "key $_\n"; } (keys %yfm_keys);
|
||||||
$yfm_skip_array = $self->{options}{'yfm_skip_array'};
|
$yfm_skip_array = $self->{options}{'yfm_skip_array'};
|
||||||
|
$yfm_lenient = $self->{options}{'yfm_lenient'};
|
||||||
} else {
|
} else {
|
||||||
foreach my $opt (qw(yfm_keys yfm_skip_array)) {
|
foreach my $opt (qw(yfm_keys yfm_lenient yfm_skip_array)) {
|
||||||
die wrap_mod( "po4a::text", dgettext( "po4a", "Option %s is only valid when parsing markdown files." ),
|
die wrap_mod( "po4a::text", dgettext( "po4a", "Option %s is only valid when parsing markdown files." ),
|
||||||
$opt )
|
$opt )
|
||||||
if exists $options{$opt};
|
if exists $options{$opt};
|
||||||
|
@ -301,12 +336,12 @@ sub parse_fallback {
|
||||||
if (
|
if (
|
||||||
$markdown
|
$markdown
|
||||||
and (
|
and (
|
||||||
$line =~ /\S $/ # explicit newline
|
$line =~ /\S $/ # explicit newline
|
||||||
or $line =~ /"""$/
|
or $line =~ /"""$/
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{ # """ textblock inside macro begin
|
{ # """ textblock inside macro begin
|
||||||
# Markdown markup needing separation _after_ this line
|
# Markdown markup needing separation _after_ this line
|
||||||
$end_of_paragraph = 1;
|
$end_of_paragraph = 1;
|
||||||
} else {
|
} else {
|
||||||
undef $self->{bullet};
|
undef $self->{bullet};
|
||||||
|
@ -576,18 +611,59 @@ sub parse_markdown_bibliographic_information {
|
||||||
sub parse_markdown_yaml_front_matter {
|
sub parse_markdown_yaml_front_matter {
|
||||||
my ( $self, $line, $blockref ) = @_;
|
my ( $self, $line, $blockref ) = @_;
|
||||||
my $yfm;
|
my $yfm;
|
||||||
|
my @saved_ctn;
|
||||||
my ( $nextline, $nextref ) = $self->shiftline();
|
my ( $nextline, $nextref ) = $self->shiftline();
|
||||||
|
push @saved_ctn, ( $nextline, $nextref );
|
||||||
while ( defined($nextline) ) {
|
while ( defined($nextline) ) {
|
||||||
last if ( $nextline =~ /^(---|\.\.\.)$/ );
|
last if ( $nextline =~ /^(---|\.\.\.)$/ );
|
||||||
$yfm .= $nextline;
|
$yfm .= $nextline;
|
||||||
( $nextline, $nextref ) = $self->shiftline();
|
( $nextline, $nextref ) = $self->shiftline();
|
||||||
|
push @saved_ctn, ( $nextline, $nextref );
|
||||||
}
|
}
|
||||||
die "Could not get the YAML Front Matter from the file." if ( length($yfm) == 0 );
|
|
||||||
my $yamlarray = YAML::Tiny->read_string($yfm)
|
|
||||||
|| die "Couldn't read YAML Front Matter ($!)\n$yfm\n";
|
|
||||||
|
|
||||||
$self->handle_yaml( $blockref, $yamlarray, \%yfm_keys, $yfm_skip_array );
|
my $yamlarray; # the parsed YFM content
|
||||||
return;
|
my $yamlres; # containing the parse error, if any
|
||||||
|
try {
|
||||||
|
$yamlarray = YAML::Tiny->read_string($yfm);
|
||||||
|
} catch {
|
||||||
|
$yamlres = $@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined($yamlres) ) {
|
||||||
|
if ($yfm_lenient) {
|
||||||
|
$yamlres =~ s/ at .*$//; # Remove the error localisation in YAML::Tiny die message, if any (for our test)
|
||||||
|
warn wrap_mod(
|
||||||
|
"po4a::text",
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"Proceeding even if the YAML Front Matter could not be parsed. Remove the 'yfm_lenient' option for a stricter behavior.\nIgnored error: %s"
|
||||||
|
),
|
||||||
|
$yamlres
|
||||||
|
);
|
||||||
|
my $len = ( scalar @saved_ctn ) - 1;
|
||||||
|
while ( $len >= 0 ) {
|
||||||
|
$self->unshiftline( $saved_ctn[ $len - 1 ], $saved_ctn[$len] );
|
||||||
|
|
||||||
|
# print STDERR "Unshift ".$saved_ctn[ $len - 1] ." | ". $saved_ctn[$len] ."\n";
|
||||||
|
$len -= 2;
|
||||||
|
}
|
||||||
|
return 0; # Not a valid YAML
|
||||||
|
} else {
|
||||||
|
die wrap_mod(
|
||||||
|
"po4a::text",
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"Could not get the YAML Front Matter from the file. If you did not intend to add a YAML front matter "
|
||||||
|
. "but an horizontal ruler, please use '----' instead, or pass the 'yfm_lenient' option.\nError: %s\nContent of the YFM: %s"
|
||||||
|
),
|
||||||
|
$yamlres, $yfm
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->handle_yaml( 1, $blockref, $yamlarray, \%yfm_keys, $yfm_skip_array, \%yfm_paths );
|
||||||
|
$self->pushline("---\n");
|
||||||
|
return 1; # Valid YAML
|
||||||
}
|
}
|
||||||
|
|
||||||
sub parse_markdown {
|
sub parse_markdown {
|
||||||
|
@ -602,8 +678,11 @@ sub parse_markdown {
|
||||||
parse_markdown_bibliographic_information( $self, $line, $ref );
|
parse_markdown_bibliographic_information( $self, $line, $ref );
|
||||||
return ( $paragraph, $wrapped_mode, $expect_header, $end_of_paragraph );
|
return ( $paragraph, $wrapped_mode, $expect_header, $end_of_paragraph );
|
||||||
} elsif ( $line =~ /^---$/ ) {
|
} elsif ( $line =~ /^---$/ ) {
|
||||||
parse_markdown_yaml_front_matter( $self, $line, $ref );
|
if ( parse_markdown_yaml_front_matter( $self, $line, $ref ) ) { # successfully parsed
|
||||||
return ( $paragraph, $wrapped_mode, $expect_header, $end_of_paragraph );
|
return ( $paragraph, $wrapped_mode, $expect_header, $end_of_paragraph );
|
||||||
|
}
|
||||||
|
|
||||||
|
# If it wasn't a YFM paragraph after all, stop expecting a header and keep going
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ( $line =~ m/^(={4,}|-{4,})$/ )
|
if ( ( $line =~ m/^(={4,}|-{4,})$/ )
|
||||||
|
@ -682,6 +761,68 @@ sub parse_markdown {
|
||||||
$self->pushline($nextline);
|
$self->pushline($nextline);
|
||||||
$paragraph = "";
|
$paragraph = "";
|
||||||
$end_of_paragraph = 1;
|
$end_of_paragraph = 1;
|
||||||
|
} elsif ( $line =~ /^([ ]{0,3})(([:])\3{2,})(\s*)([^`]*)\s*$/ ) {
|
||||||
|
my $fence_space_before = $1;
|
||||||
|
my $fence = $2;
|
||||||
|
my $fencechar = $3;
|
||||||
|
my $fence_space_between = $4;
|
||||||
|
my @info_string = ($5);
|
||||||
|
|
||||||
|
# print STDERR "----------------\n";
|
||||||
|
# print STDERR "line: $line\n";
|
||||||
|
# print STDERR "fence: '$fence'; fencechar: '$fencechar'; info: '$info_string'\n";
|
||||||
|
|
||||||
|
# fenced div block (fenced with ::: where code blocks are fenced with ` or ~)
|
||||||
|
# https://pandoc.org/MANUAL.html#divs-and-spans
|
||||||
|
my $info = join( "|" , map {chomp $_;$_} @info_string );
|
||||||
|
my $type = "Fenced div block" . ( $info ? " ($info)" : "" );
|
||||||
|
do_paragraph( $self, $paragraph, $wrapped_mode );
|
||||||
|
$wrapped_mode = 0;
|
||||||
|
$paragraph = "";
|
||||||
|
$self->pushline("$line\n");
|
||||||
|
do_paragraph( $self, $paragraph, $wrapped_mode );
|
||||||
|
$paragraph = "";
|
||||||
|
|
||||||
|
my $lvl = 1;
|
||||||
|
while ( $lvl > 0 ) {
|
||||||
|
my ( $nextline, $nextref ) = $self->shiftline();
|
||||||
|
die wrap_mod(
|
||||||
|
"po4a::text",
|
||||||
|
dgettext(
|
||||||
|
"po4a", "Malformed fenced div block: Block starting at %s not closed before the end of the file."
|
||||||
|
),
|
||||||
|
$ref
|
||||||
|
) unless ( defined($nextline) );
|
||||||
|
|
||||||
|
# print STDERR "within $lvl: $nextline";
|
||||||
|
if ( $nextline =~ /^\s*:::+\s*$/ ) {
|
||||||
|
my $info = join( "|" , map {chomp $_;$_} @info_string );
|
||||||
|
$type = "Fenced div block" . ( $info ? " ($info)" : "" );
|
||||||
|
if ($paragraph ne "") {
|
||||||
|
do_paragraph( $self, $paragraph, $wrapped_mode, $type );
|
||||||
|
$paragraph = "";
|
||||||
|
}
|
||||||
|
$self->pushline($nextline);
|
||||||
|
$lvl--;
|
||||||
|
while (scalar @info_string > $lvl) {
|
||||||
|
pop @info_string;
|
||||||
|
}
|
||||||
|
} elsif ( $nextline =~ /^([ ]{0,3})(([:])\3{2,})(\s*)([^`]*)\s*$/ ) {
|
||||||
|
if ($paragraph ne "") {
|
||||||
|
do_paragraph( $self, $paragraph, $wrapped_mode, $type );
|
||||||
|
$paragraph = "";
|
||||||
|
}
|
||||||
|
$self->pushline($nextline);
|
||||||
|
push @info_string, $5;
|
||||||
|
$lvl++;
|
||||||
|
} else {
|
||||||
|
$paragraph .= $nextline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$paragraph = "";
|
||||||
|
$end_of_paragraph = 1;
|
||||||
|
|
||||||
|
# print STDERR "Out now ------------\n";
|
||||||
} elsif (
|
} elsif (
|
||||||
$line =~ /^\s*\[\[\!\S+\s*$/ # macro begin
|
$line =~ /^\s*\[\[\!\S+\s*$/ # macro begin
|
||||||
or $line =~ /^\s*"""\s*\]\]\s*$/
|
or $line =~ /^\s*"""\s*\]\]\s*$/
|
||||||
|
@ -698,8 +839,8 @@ sub parse_markdown {
|
||||||
$paragraph = "$line\n";
|
$paragraph = "$line\n";
|
||||||
$wrapped_mode = 0;
|
$wrapped_mode = 0;
|
||||||
$end_of_paragraph = 1;
|
$end_of_paragraph = 1;
|
||||||
} elsif ( $line =~ /^"""/ ) { # """ textblock inside macro end
|
} elsif ( $line =~ /^"""/ ) { # """ textblock inside macro end
|
||||||
# Markdown markup needing separation _before_ this line
|
# Markdown markup needing separation _before_ this line
|
||||||
do_paragraph( $self, $paragraph, $wrapped_mode );
|
do_paragraph( $self, $paragraph, $wrapped_mode );
|
||||||
$paragraph = "$line\n";
|
$paragraph = "$line\n";
|
||||||
$wrapped_mode = $defaultwrap;
|
$wrapped_mode = $defaultwrap;
|
||||||
|
@ -787,15 +928,10 @@ sub do_paragraph {
|
||||||
$wrap = 0 unless $defaultwrap;
|
$wrap = 0 unless $defaultwrap;
|
||||||
|
|
||||||
# DEBUG
|
# DEBUG
|
||||||
# my $b;
|
# $type .= " verbatim: '".($self->{verbatim}//"NONE")."' bullet: '$bullets' wrap: '$wrap' indent: '".($self->{indent}//"NONE")."' type: '".($self->{type}//"NONE")."'";
|
||||||
# if (defined $self->{bullet}) {
|
# print STDERR "$type\n";
|
||||||
# $b = $self->{bullet};
|
|
||||||
# } else {
|
|
||||||
# $b = "UNDEF";
|
|
||||||
# }
|
|
||||||
# $type .= " verbatim: '".($self->{verbatim}||"NONE")."' bullet: '$b' indent: '".($self->{indent}||"NONE")."' type: '".($self->{type}||"NONE")."'";
|
|
||||||
|
|
||||||
if ( $bullets and not $wrap and not defined $self->{verbatim} ) {
|
if ( $bullets and not defined $self->{verbatim} ) {
|
||||||
|
|
||||||
# Detect bullets
|
# Detect bullets
|
||||||
# | * blah blah
|
# | * blah blah
|
||||||
|
@ -803,7 +939,7 @@ sub do_paragraph {
|
||||||
# | ^-- aligned
|
# | ^-- aligned
|
||||||
# <empty line>
|
# <empty line>
|
||||||
#
|
#
|
||||||
# Other bullets supported:
|
# The leading spaces are optional, and other bullets are supported:
|
||||||
# - blah o blah + blah
|
# - blah o blah + blah
|
||||||
# 1. blah 1) blah (1) blah
|
# 1. blah 1) blah (1) blah
|
||||||
TEST_BULLET:
|
TEST_BULLET:
|
||||||
|
@ -896,3 +1032,7 @@ This program is free software; you may redistribute it and/or modify it
|
||||||
under the terms of GPL (see the COPYING file).
|
under the terms of GPL (see the COPYING file).
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
# LocalWords: Charset charset po UTF gettext msgid nostrip GPL
|
||||||
|
|
|
@ -11,7 +11,7 @@ use warnings;
|
||||||
|
|
||||||
use subs qw(makespace);
|
use subs qw(makespace);
|
||||||
use vars qw($VERSION @ISA @EXPORT);
|
use vars qw($VERSION @ISA @EXPORT);
|
||||||
$VERSION = "0.66";
|
$VERSION = "0.69";
|
||||||
@ISA = qw(DynaLoader);
|
@ISA = qw(DynaLoader);
|
||||||
@EXPORT = qw(new process translate
|
@EXPORT = qw(new process translate
|
||||||
read write readpo writepo
|
read write readpo writepo
|
||||||
|
@ -544,11 +544,6 @@ of use:
|
||||||
($percent,$hit,$queries) = $document->stats();
|
($percent,$hit,$queries) = $document->stats();
|
||||||
print "We found translations for $percent\% ($hit from $queries) of strings.\n";
|
print "We found translations for $percent\% ($hit from $queries) of strings.\n";
|
||||||
|
|
||||||
=item is_po_uptodate()
|
|
||||||
|
|
||||||
Returns ($uptodate, $diagnostic) where $uptodate is whether the input po and the output po match (if not, it means that the input po should be updated)
|
|
||||||
and $diagnostic is a string explaining why the po file is not uptodate, when this happens.
|
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
@ -573,10 +568,6 @@ sub stats {
|
||||||
return $_[0]->{TT}{po_in}->stats_get();
|
return $_[0]->{TT}{po_in}->stats_get();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub is_po_uptodate($) {
|
|
||||||
return $_[0]->{TT}{po_in}->equals_msgid( $_[0]->{TT}{po_out} );
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 Manipulating addenda
|
=head2 Manipulating addenda
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
@ -1186,11 +1177,12 @@ sub encode_from_to {
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Push the translation of a Yaml Front-Matter header that was parsed by YAML::Tiny
|
# Push the translation of a Yaml document or Yaml Front-Matter header, parsed by YAML::Tiny in any case
|
||||||
|
# $is_yfm is a boolean indicating whether we are dealing with a Front Matter (true value) or whole document (false value)
|
||||||
sub handle_yaml {
|
sub handle_yaml {
|
||||||
my ( $self, $blockref, $yamlarray, $yfm_keys, $yfm_skip_array ) = @_;
|
my ( $self, $is_yfm, $blockref, $yamlarray, $yfm_keys, $yfm_skip_array, $yfm_paths ) = @_;
|
||||||
|
|
||||||
die "Empty YAML Front Matter" unless ( length($yamlarray) > 0 );
|
die "Empty YAML " . ($is_yfm?"Front Matter":"document") unless ( length($yamlarray) > 0 );
|
||||||
|
|
||||||
my ( $indent, $ctx ) = ( 0, "" );
|
my ( $indent, $ctx ) = ( 0, "" );
|
||||||
foreach my $cursor (@$yamlarray) {
|
foreach my $cursor (@$yamlarray) {
|
||||||
|
@ -1205,13 +1197,13 @@ sub handle_yaml {
|
||||||
} elsif ( !ref $cursor ) {
|
} elsif ( !ref $cursor ) {
|
||||||
$self->pushline("---\n");
|
$self->pushline("---\n");
|
||||||
$self->pushline(
|
$self->pushline(
|
||||||
format_scalar( $self->translate( $cursor, $blockref, "YAML Front Matter (scalar)", "wrap" => 0 ) ) );
|
format_scalar( $self->translate( $cursor, $blockref, "YAML ".($is_yfm?"Front Matter ":"")."(scalar)", "wrap" => 0 ) ) );
|
||||||
|
|
||||||
# A list at the root
|
# A list at the root
|
||||||
} elsif ( ref $cursor eq 'ARRAY' ) {
|
} elsif ( ref $cursor eq 'ARRAY' ) {
|
||||||
if (@$cursor) {
|
if (@$cursor) {
|
||||||
$self->pushline("---\n");
|
$self->pushline("---\n");
|
||||||
do_array( $self, $blockref, $cursor, $indent, $ctx, $yfm_keys, $yfm_skip_array );
|
do_array( $self, $is_yfm, $blockref, $cursor, $indent, $ctx, $yfm_keys, $yfm_skip_array, $yfm_paths );
|
||||||
} else {
|
} else {
|
||||||
$self->pushline("---[]\n");
|
$self->pushline("---[]\n");
|
||||||
}
|
}
|
||||||
|
@ -1220,7 +1212,7 @@ sub handle_yaml {
|
||||||
} elsif ( ref $cursor eq 'HASH' ) {
|
} elsif ( ref $cursor eq 'HASH' ) {
|
||||||
if (%$cursor) {
|
if (%$cursor) {
|
||||||
$self->pushline("---\n");
|
$self->pushline("---\n");
|
||||||
do_hash( $self, $blockref, $cursor, $indent, $ctx, $yfm_keys, $yfm_skip_array );
|
do_hash( $self, $is_yfm, $blockref, $cursor, $indent, $ctx, $yfm_keys, $yfm_skip_array, $yfm_paths );
|
||||||
} else {
|
} else {
|
||||||
$self->pushline("--- {}\n");
|
$self->pushline("--- {}\n");
|
||||||
}
|
}
|
||||||
|
@ -1228,7 +1220,6 @@ sub handle_yaml {
|
||||||
} else {
|
} else {
|
||||||
die( "Cannot serialize " . ref($cursor) );
|
die( "Cannot serialize " . ref($cursor) );
|
||||||
}
|
}
|
||||||
$self->pushline("---\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Escape the string to make it valid in YAML.
|
# Escape the string to make it valid in YAML.
|
||||||
|
@ -1262,7 +1253,7 @@ sub handle_yaml {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub do_array {
|
sub do_array {
|
||||||
my ( $self, $blockref, $array, $indent, $ctx, $yfm_keys, $yfm_skip_array ) = @_;
|
my ( $self, $is_yfm, $blockref, $array, $indent, $ctx, $yfm_keys, $yfm_skip_array, $yfm_paths ) = @_;
|
||||||
foreach my $el (@$array) {
|
foreach my $el (@$array) {
|
||||||
my $header = ( ' ' x $indent ) . '- ';
|
my $header = ( ' ' x $indent ) . '- ';
|
||||||
my $type = ref $el;
|
my $type = ref $el;
|
||||||
|
@ -1271,14 +1262,14 @@ sub handle_yaml {
|
||||||
$self->pushline( $header . YAML::Tiny::_dump_scalar( "dummy", $el, 0 ) . "\n" );
|
$self->pushline( $header . YAML::Tiny::_dump_scalar( "dummy", $el, 0 ) . "\n" );
|
||||||
} else {
|
} else {
|
||||||
$self->pushline( $header
|
$self->pushline( $header
|
||||||
. format_scalar( $self->translate( $el, $blockref, "YAML Front Matter:$ctx", "wrap" => 0 ) )
|
. format_scalar( $self->translate( $el, $blockref, ($is_yfm?"Yaml Front Matter ":"")."Array Element:$ctx", "wrap" => 0 ) )
|
||||||
. "\n" );
|
. "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
} elsif ( $type eq 'ARRAY' ) {
|
} elsif ( $type eq 'ARRAY' ) {
|
||||||
if (@$el) {
|
if (@$el) {
|
||||||
$self->pushline( $header . "\n" );
|
$self->pushline( $header . "\n" );
|
||||||
do_array( $self, $blockref, $el, $indent + 1, $ctx, $yfm_keys, $yfm_skip_array );
|
do_array( $self, $is_yfm, $blockref, $el, $indent + 1, $ctx, $yfm_keys, $yfm_skip_array, $yfm_paths );
|
||||||
} else {
|
} else {
|
||||||
$self->pushline( $header . " []\n" );
|
$self->pushline( $header . " []\n" );
|
||||||
}
|
}
|
||||||
|
@ -1286,7 +1277,7 @@ sub handle_yaml {
|
||||||
} elsif ( $type eq 'HASH' ) {
|
} elsif ( $type eq 'HASH' ) {
|
||||||
if ( keys %$el ) {
|
if ( keys %$el ) {
|
||||||
$self->pushline( $header . "\n" );
|
$self->pushline( $header . "\n" );
|
||||||
do_hash( $self, $blockref, $el, $indent + 1, $ctx, $yfm_keys, $yfm_skip_array );
|
do_hash( $self, $is_yfm, $blockref, $el, $indent + 1, $ctx, $yfm_keys, $yfm_skip_array, $yfm_paths );
|
||||||
} else {
|
} else {
|
||||||
$self->pushline( $header . " {}\n" );
|
$self->pushline( $header . " {}\n" );
|
||||||
}
|
}
|
||||||
|
@ -1298,28 +1289,38 @@ sub handle_yaml {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub do_hash {
|
sub do_hash {
|
||||||
my ( $self, $blockref, $hash, $indent, $ctx, $yfm_keys, $yfm_skip_array ) = @_;
|
my ( $self, $is_yfm, $blockref, $hash, $indent, $ctx, $yfm_keys, $yfm_skip_array, $yfm_paths ) = @_;
|
||||||
|
|
||||||
foreach my $name ( sort keys %$hash ) {
|
foreach my $name ( sort keys %$hash ) {
|
||||||
my $el = $hash->{$name};
|
my $el = $hash->{$name};
|
||||||
my $header = ( ' ' x $indent ) . YAML::Tiny::_dump_scalar( "dummy", $name, 1 ) . ":";
|
my $header = ( ' ' x $indent ) . YAML::Tiny::_dump_scalar( "dummy", $name, 1 ) . ":";
|
||||||
my $type = ref $el;
|
my $type = ref $el;
|
||||||
if ( !$type ) {
|
if ( !$type ) {
|
||||||
my %keys = %{$yfm_keys};
|
my %keys = %{$yfm_keys};
|
||||||
if ( ( not %keys ) || $keys{$name} ) { # either no key is provided, or the key we need is also provided
|
my %paths = %{$yfm_paths};
|
||||||
$self->pushline(
|
my $path = "$ctx $name" =~ s/^\s+|\s+$//gr; # Need to trim the path, at least when there is no ctx yet
|
||||||
$header . ' '
|
|
||||||
. format_scalar(
|
if ( ($el eq 'false') or ($el eq 'true') ) { # Do not translate not quote booleans
|
||||||
$self->translate( $el, $blockref, "YAML Front Matter:$ctx $name", "wrap" => 0 )
|
$self->pushline("$header $el\n");
|
||||||
)
|
} elsif ( ( scalar %keys > 0 && exists $keys{$name}) or # the key we need is provided
|
||||||
. "\n"
|
( scalar %paths > 0 && exists $paths{$path}) or # that path is provided
|
||||||
);
|
( scalar %keys == 0 && scalar %paths == 0) ) { # no key and no path provided
|
||||||
|
my $translation = $self->translate( $el, $blockref, ($is_yfm?"Yaml Front Matter ":"")."Hash Value:$ctx $name", "wrap" => 0 );
|
||||||
|
if ( $el =~ /^\[.*\]$/ ) { # Do not quote the lists
|
||||||
|
$self->pushline( $header . " $translation\n" );
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# add extra quotes to the parameter, as a protection to the extra chars that the translator could add
|
||||||
|
$self->pushline( $header . ' ' . format_scalar($translation) . "\n" );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
# Work around a bug in YAML::Tiny that quotes numbers
|
# Work around a bug in YAML::Tiny that quotes numbers
|
||||||
# See https://github.com/Perl-Toolchain-Gang/YAML-Tiny#additional-perl-specific-notes
|
# See https://github.com/Perl-Toolchain-Gang/YAML-Tiny#additional-perl-specific-notes
|
||||||
if ( Scalar::Util::looks_like_number($el) ) {
|
if ( Scalar::Util::looks_like_number($el) ) {
|
||||||
$self->pushline("$header $el\n");
|
$self->pushline("$header $el\n");
|
||||||
|
} elsif ( $el =~ /^\[.*\]$/ ) { # Do not quote the lists either
|
||||||
|
$self->pushline("$header $el\n");
|
||||||
} else {
|
} else {
|
||||||
$self->pushline( $header . ' ' . YAML::Tiny::_dump_scalar( "dummy", $el ) . "\n" );
|
$self->pushline( $header . ' ' . YAML::Tiny::_dump_scalar( "dummy", $el ) . "\n" );
|
||||||
}
|
}
|
||||||
|
@ -1328,7 +1329,7 @@ sub handle_yaml {
|
||||||
} elsif ( $type eq 'ARRAY' ) {
|
} elsif ( $type eq 'ARRAY' ) {
|
||||||
if (@$el) {
|
if (@$el) {
|
||||||
$self->pushline( $header . "\n" );
|
$self->pushline( $header . "\n" );
|
||||||
do_array( $self, $blockref, $el, $indent + 1, "$ctx $name", $yfm_keys, $yfm_skip_array );
|
do_array( $self, $is_yfm, $blockref, $el, $indent + 1, "$ctx $name", $yfm_keys, $yfm_skip_array, $yfm_paths );
|
||||||
} else {
|
} else {
|
||||||
$self->pushline( $header . " []\n" );
|
$self->pushline( $header . " []\n" );
|
||||||
}
|
}
|
||||||
|
@ -1336,7 +1337,7 @@ sub handle_yaml {
|
||||||
} elsif ( $type eq 'HASH' ) {
|
} elsif ( $type eq 'HASH' ) {
|
||||||
if ( keys %$el ) {
|
if ( keys %$el ) {
|
||||||
$self->pushline( $header . "\n" );
|
$self->pushline( $header . "\n" );
|
||||||
do_hash( $self, $blockref, $el, $indent + 1, "$ctx $name", $yfm_keys, $yfm_skip_array );
|
do_hash( $self, $is_yfm, $blockref, $el, $indent + 1, "$ctx $name", $yfm_keys, $yfm_skip_array, $yfm_paths );
|
||||||
} else {
|
} else {
|
||||||
$self->pushline( $header . " {}\n" );
|
$self->pushline( $header . " {}\n" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ sub read {
|
||||||
my $tmp_filename;
|
my $tmp_filename;
|
||||||
( undef, $tmp_filename ) = File::Temp::tempfile(
|
( undef, $tmp_filename ) = File::Temp::tempfile(
|
||||||
"po4aXXXX",
|
"po4aXXXX",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
SUFFIX => ".xml",
|
SUFFIX => ".xml",
|
||||||
OPEN => 0,
|
OPEN => 0,
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
|
|
|
@ -66,8 +66,7 @@ This module is fully functional, as it relies in the L<Locale::Po4a::Xml>
|
||||||
module. This only defines the translatable tags and attributes.
|
module. This only defines the translatable tags and attributes.
|
||||||
|
|
||||||
"It works for me", which means I use it successfully on my personal Web site.
|
"It works for me", which means I use it successfully on my personal Web site.
|
||||||
However, YMMV: please let me know if something doesn't work for you. In
|
However, YMMV: please let me know if something doesn't work for you.
|
||||||
particular, tables are getting no testing whatsoever, as we don't use them.
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
|
|
@ -1071,7 +1071,7 @@ sub CDATA_trans {
|
||||||
sub tag_break_alone {
|
sub tag_break_alone {
|
||||||
my ( $self, @tag ) = @_;
|
my ( $self, @tag ) = @_;
|
||||||
my $struct = $self->get_path( $self->get_tag_name(@tag) );
|
my $struct = $self->get_path( $self->get_tag_name(@tag) );
|
||||||
if ( $self->get_translate_options($struct) =~ m/i/ ) {
|
if ( $self->get_translate_options($struct) =~ m/[ip]/ ) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1701,140 +1701,16 @@ sub treat_content {
|
||||||
# Append or remove the opening/closing tag from the tag path
|
# Append or remove the opening/closing tag from the tag path
|
||||||
if ( $tag_types[$type]->{'end'} eq "" ) {
|
if ( $tag_types[$type]->{'end'} eq "" ) {
|
||||||
if ( $tag_types[$type]->{'beginning'} eq "" ) {
|
if ( $tag_types[$type]->{'beginning'} eq "" ) {
|
||||||
|
$self->treat_content_open_tag(\@tag, \@paragraph, \@text);
|
||||||
# tag is <tag >
|
|
||||||
my $cur_tag_name = $self->get_tag_name(@tag);
|
|
||||||
my $t_opts = $self->get_translate_options( $self->get_path($cur_tag_name) );
|
|
||||||
if ( $t_opts =~ m/p/ ) {
|
|
||||||
|
|
||||||
# tag has a placeholder option, append a "<placeholder
|
|
||||||
# type=cur_tag_name id =id_index>" tag to @paragraph.
|
|
||||||
# using $self->get_tag_name(@tag) as cur_tag_name and
|
|
||||||
# using $#{$save_holders[$#save_holders]->{'sub_translations'}} + 1
|
|
||||||
# as id_index
|
|
||||||
my $last_holder = $save_holders[$#save_holders];
|
|
||||||
my $placeholder_str =
|
|
||||||
"<placeholder type=\""
|
|
||||||
. $cur_tag_name
|
|
||||||
. "\" id=\""
|
|
||||||
. ( $#{ $last_holder->{'sub_translations'} } + 1 ) . "\"/>";
|
|
||||||
push @paragraph, ( $placeholder_str, $text[1] );
|
|
||||||
my @saved_paragraph = @paragraph;
|
|
||||||
|
|
||||||
$last_holder->{'paragraph'} = \@saved_paragraph;
|
|
||||||
|
|
||||||
# Then we must push a new holder into @save_holders
|
|
||||||
my @new_paragraph = ();
|
|
||||||
my @sub_translations = ();
|
|
||||||
my %folded_attributes;
|
|
||||||
my %new_holder = (
|
|
||||||
'paragraph' => \@new_paragraph,
|
|
||||||
'open' => $self->join_lines(@text),
|
|
||||||
'translation' => "",
|
|
||||||
'close' => undef,
|
|
||||||
'sub_translations' => \@sub_translations,
|
|
||||||
'folded_attributes' => \%folded_attributes
|
|
||||||
);
|
|
||||||
push @save_holders, \%new_holder;
|
|
||||||
|
|
||||||
# reset @text holding the whole tag with attributes
|
|
||||||
# to empty
|
|
||||||
@text = ();
|
|
||||||
|
|
||||||
# reset the current @paragraph (for the current holder)
|
|
||||||
# to empty.
|
|
||||||
@paragraph = ();
|
|
||||||
|
|
||||||
} elsif ( $t_opts =~ m/f/ ) {
|
|
||||||
|
|
||||||
# tag has a "f" option for folded attributes
|
|
||||||
my $tag_full = $self->join_lines(@text);
|
|
||||||
my $tag_ref = $text[1];
|
|
||||||
if ( $tag_full =~ m/^<\s*\S+\s+\S.*>$/s ) {
|
|
||||||
my $holder = $save_holders[$#save_holders];
|
|
||||||
my $id = 0;
|
|
||||||
foreach ( keys %{ $holder->{folded_attributes} } ) {
|
|
||||||
$id = $_ + 1 if ( $_ >= $id );
|
|
||||||
}
|
|
||||||
$holder->{folded_attributes}->{$id} = $tag_full;
|
|
||||||
|
|
||||||
@text = ( "<$cur_tag_name po4a-id=$id>", $tag_ref );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unless ( $t_opts =~ m/n/ ) {
|
|
||||||
|
|
||||||
# unless "n" for custom (such as non-XML HTML) tag, update @path
|
|
||||||
push @path, $cur_tag_name;
|
|
||||||
}
|
|
||||||
} elsif ( $tag_types[$type]->{'beginning'} eq "/" ) {
|
} elsif ( $tag_types[$type]->{'beginning'} eq "/" ) {
|
||||||
|
$self->treat_content_close_tag(\@tag, \@paragraph, \@text);
|
||||||
# tag is </tag>
|
|
||||||
|
|
||||||
# Verify this closing tag matches with the last opening tag
|
|
||||||
# while removing the last opening tag in @path
|
|
||||||
my $test = pop @path;
|
|
||||||
my $name = $self->get_tag_name(@tag);
|
|
||||||
if ( !defined($test)
|
|
||||||
|| $test ne $name )
|
|
||||||
{
|
|
||||||
my $ontagerror = $self->{options}{'ontagerror'};
|
|
||||||
if ( $ontagerror eq "warn" ) {
|
|
||||||
warn wrap_ref_mod(
|
|
||||||
$tag[1],
|
|
||||||
"po4a::xml",
|
|
||||||
dgettext(
|
|
||||||
"po4a",
|
|
||||||
"Unexpected closing tag </%s> found. The main document may be wrong. Continuing…"
|
|
||||||
),
|
|
||||||
$name
|
|
||||||
);
|
|
||||||
} elsif ( $ontagerror ne "silent" ) {
|
|
||||||
die wrap_ref_mod(
|
|
||||||
$tag[1],
|
|
||||||
"po4a::xml",
|
|
||||||
dgettext(
|
|
||||||
"po4a", "Unexpected closing tag </%s> found. The main document may be wrong."
|
|
||||||
),
|
|
||||||
$name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $self->get_translate_options( $self->get_path( $self->get_tag_name(@tag) ) ) =~ m/p/ ) {
|
|
||||||
|
|
||||||
# this closing tag has a placeholder option
|
|
||||||
|
|
||||||
# revert @path to include this tag for translate_paragraph
|
|
||||||
push @path, $self->get_tag_name(@tag);
|
|
||||||
|
|
||||||
# Now translate this paragraph if needed.
|
|
||||||
# This will call pushline and append the
|
|
||||||
# translation to the current holder's translation.
|
|
||||||
$self->translate_paragraph(@paragraph);
|
|
||||||
|
|
||||||
# remove this tag from @path
|
|
||||||
pop @path;
|
|
||||||
|
|
||||||
# Now that this holder is closed, we can remove
|
|
||||||
# the holder from the stack.
|
|
||||||
my $holder = pop @save_holders;
|
|
||||||
|
|
||||||
# We need to keep the translation of this holder
|
|
||||||
my $translation = $holder->{'open'} . $holder->{'translation'};
|
|
||||||
$translation .= $self->join_lines(@text);
|
|
||||||
|
|
||||||
@text = ();
|
|
||||||
|
|
||||||
# Then we store the translation in the previous
|
|
||||||
# holder's sub_translations array
|
|
||||||
my $previous_holder = $save_holders[$#save_holders];
|
|
||||||
push @{ $previous_holder->{'sub_translations'} }, $translation;
|
|
||||||
|
|
||||||
# We also need to restore the @paragraph array, as
|
|
||||||
# it was before we encountered the holder.
|
|
||||||
@paragraph = @{ $previous_holder->{'paragraph'} };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} elsif ( $tag_types[$type]->{'beginning'} eq ""
|
||||||
|
&& $tag_types[$type]->{'end'} eq "/" ) {
|
||||||
|
# As for empty-element tag,
|
||||||
|
# treat as if both open and close tags exist
|
||||||
|
$self->treat_content_open_tag(\@tag, \@paragraph, \@text);
|
||||||
|
$self->treat_content_close_tag(\@tag, \@paragraph, \@text);
|
||||||
}
|
}
|
||||||
push @paragraph, @text;
|
push @paragraph, @text;
|
||||||
}
|
}
|
||||||
|
@ -1908,6 +1784,174 @@ sub treat_content {
|
||||||
return $eof;
|
return $eof;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Processes open tags during getting texts.
|
||||||
|
# Performs special process for placeholder and attribute folding.
|
||||||
|
sub treat_content_open_tag {
|
||||||
|
my $self = shift;
|
||||||
|
my ($tag, $paragraph, $text) = @_;
|
||||||
|
|
||||||
|
# tag is <tag >
|
||||||
|
my $cur_tag_name = $self->get_tag_name(@$tag);
|
||||||
|
my $t_opts = $self->get_translate_options( $self->get_path($cur_tag_name) );
|
||||||
|
if ( $t_opts =~ m/p/ ) {
|
||||||
|
|
||||||
|
# tag has a placeholder option, append a "<placeholder
|
||||||
|
# type=cur_tag_name id =id_index>" tag to @$paragraph.
|
||||||
|
# using $self->get_tag_name(@$tag) as cur_tag_name and
|
||||||
|
# using $#{$save_holders[$#save_holders]->{'sub_translations'}} + 1
|
||||||
|
# as id_index
|
||||||
|
my $last_holder = $save_holders[$#save_holders];
|
||||||
|
my $placeholder_str =
|
||||||
|
"<placeholder type=\""
|
||||||
|
. $cur_tag_name
|
||||||
|
. "\" id=\""
|
||||||
|
. ( $#{ $last_holder->{'sub_translations'} } + 1 ) . "\"/>";
|
||||||
|
push @$paragraph, ( $placeholder_str, $text->[1] );
|
||||||
|
my @saved_paragraph = @$paragraph;
|
||||||
|
|
||||||
|
$last_holder->{'paragraph'} = \@saved_paragraph;
|
||||||
|
|
||||||
|
# make attributes be able to be translated
|
||||||
|
my $open_tag = $self->join_lines(@$text);
|
||||||
|
if ($open_tag =~ m/^<(\s*)(\S+\s+\S.*)>$/s) {
|
||||||
|
my ($ws, $tag_inner) = ($1, $2);
|
||||||
|
$tag_inner =~ s|(\s*/)$||;
|
||||||
|
my $postfix = $1;
|
||||||
|
push @path, $cur_tag_name;
|
||||||
|
$open_tag = "<" . $ws . $self->treat_attributes($tag_inner)
|
||||||
|
. $postfix . ">";
|
||||||
|
pop @path;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Then we must push a new holder into @save_holders
|
||||||
|
my @new_paragraph = ();
|
||||||
|
my @sub_translations = ();
|
||||||
|
my %folded_attributes;
|
||||||
|
my %new_holder = (
|
||||||
|
'paragraph' => \@new_paragraph,
|
||||||
|
'open' => $open_tag,
|
||||||
|
'translation' => "",
|
||||||
|
'close' => undef,
|
||||||
|
'sub_translations' => \@sub_translations,
|
||||||
|
'folded_attributes' => \%folded_attributes
|
||||||
|
);
|
||||||
|
push @save_holders, \%new_holder;
|
||||||
|
|
||||||
|
# reset @$text holding the whole tag with attributes
|
||||||
|
# to empty
|
||||||
|
@$text = ();
|
||||||
|
|
||||||
|
# reset the current @$paragraph (for the current holder)
|
||||||
|
# to empty.
|
||||||
|
@$paragraph = ();
|
||||||
|
|
||||||
|
} elsif ( $t_opts =~ m/f/ ) {
|
||||||
|
|
||||||
|
# tag has a "f" option for folded attributes
|
||||||
|
my $tag_full = $self->join_lines(@$text);
|
||||||
|
my $tag_ref = $text->[1];
|
||||||
|
if ( $tag_full =~ m/^<(\s*)(\S+\s+\S.*)>$/s ) {
|
||||||
|
my ($ws, $tag_inner) = ($1, $2);
|
||||||
|
my $holder = $save_holders[$#save_holders];
|
||||||
|
my $id = 0;
|
||||||
|
foreach ( keys %{ $holder->{folded_attributes} } ) {
|
||||||
|
$id = $_ + 1 if ( $_ >= $id );
|
||||||
|
}
|
||||||
|
|
||||||
|
# make attributes be able to be translated
|
||||||
|
$tag_inner =~ s|(\s*/)$||;
|
||||||
|
my $postfix = $1;
|
||||||
|
push @path, $cur_tag_name;
|
||||||
|
$holder->{folded_attributes}->{$id} =
|
||||||
|
"<" . $ws . $self->treat_attributes($tag_inner)
|
||||||
|
. $postfix . ">";
|
||||||
|
pop @path;
|
||||||
|
|
||||||
|
@$text = ( "<$cur_tag_name po4a-id=$id>", $tag_ref );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unless ( $t_opts =~ m/n/ ) {
|
||||||
|
|
||||||
|
# unless "n" for custom (such as non-XML HTML) tag, update @path
|
||||||
|
push @path, $cur_tag_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Processes close tags during getting texts.
|
||||||
|
# Performs special process for placeholder.
|
||||||
|
sub treat_content_close_tag {
|
||||||
|
my $self = shift;
|
||||||
|
my ($tag, $paragraph, $text) = @_;
|
||||||
|
|
||||||
|
# tag is </tag>
|
||||||
|
|
||||||
|
# Verify this closing tag matches with the last opening tag
|
||||||
|
# while removing the last opening tag in @path
|
||||||
|
my $test = pop @path;
|
||||||
|
my $name = $self->get_tag_name(@$tag);
|
||||||
|
if ( !defined($test)
|
||||||
|
|| $test ne $name )
|
||||||
|
{
|
||||||
|
my $ontagerror = $self->{options}{'ontagerror'};
|
||||||
|
if ( $ontagerror eq "warn" ) {
|
||||||
|
warn wrap_ref_mod(
|
||||||
|
$tag->[1],
|
||||||
|
"po4a::xml",
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"Unexpected closing tag </%s> found. The main document may be wrong. Continuing…"
|
||||||
|
),
|
||||||
|
$name
|
||||||
|
);
|
||||||
|
} elsif ( $ontagerror ne "silent" ) {
|
||||||
|
die wrap_ref_mod(
|
||||||
|
$tag->[1],
|
||||||
|
"po4a::xml",
|
||||||
|
dgettext(
|
||||||
|
"po4a", "Unexpected closing tag </%s> found. The main document may be wrong."
|
||||||
|
),
|
||||||
|
$name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $self->get_translate_options( $self->get_path( $self->get_tag_name(@$tag) ) ) =~ m/p/ ) {
|
||||||
|
|
||||||
|
# this closing tag has a placeholder option
|
||||||
|
|
||||||
|
# revert @path to include this tag for translate_paragraph
|
||||||
|
push @path, $self->get_tag_name(@$tag);
|
||||||
|
|
||||||
|
# Now translate this paragraph if needed.
|
||||||
|
# This will call pushline and append the
|
||||||
|
# translation to the current holder's translation.
|
||||||
|
$self->translate_paragraph(@$paragraph);
|
||||||
|
|
||||||
|
# remove this tag from @path
|
||||||
|
pop @path;
|
||||||
|
|
||||||
|
# Now that this holder is closed, we can remove
|
||||||
|
# the holder from the stack.
|
||||||
|
my $holder = pop @save_holders;
|
||||||
|
|
||||||
|
# We need to keep the translation of this holder
|
||||||
|
my $translation = $holder->{'open'} . $holder->{'translation'};
|
||||||
|
$translation .= $self->join_lines(@$text);
|
||||||
|
|
||||||
|
@$text = ();
|
||||||
|
|
||||||
|
# Then we store the translation in the previous
|
||||||
|
# holder's sub_translations array
|
||||||
|
my $previous_holder = $save_holders[$#save_holders];
|
||||||
|
push @{ $previous_holder->{'sub_translations'} }, $translation;
|
||||||
|
|
||||||
|
# We also need to restore the @$paragraph array, as
|
||||||
|
# it was before we encountered the holder.
|
||||||
|
@$paragraph = @{ $previous_holder->{'paragraph'} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Translate a @paragraph array of (string, reference).
|
# Translate a @paragraph array of (string, reference).
|
||||||
# The $translate argument indicates if the strings must be translated or
|
# The $translate argument indicates if the strings must be translated or
|
||||||
# just pushed
|
# just pushed
|
||||||
|
|
|
@ -4,140 +4,6 @@
|
||||||
# under the terms of GPL (see COPYING).
|
# under the terms of GPL (see COPYING).
|
||||||
#
|
#
|
||||||
|
|
||||||
############################################################################
|
|
||||||
# Modules and declarations
|
|
||||||
############################################################################
|
|
||||||
|
|
||||||
package Locale::Po4a::Yaml;
|
|
||||||
|
|
||||||
use Locale::Po4a::TransTractor;
|
|
||||||
use Locale::Po4a::Common;
|
|
||||||
use YAML::Tiny;
|
|
||||||
use Scalar::Util;
|
|
||||||
use Encode;
|
|
||||||
|
|
||||||
use 5.006;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
require Exporter;
|
|
||||||
|
|
||||||
use vars qw(@ISA @EXPORT $AUTOLOAD);
|
|
||||||
@ISA = qw(Locale::Po4a::TransTractor);
|
|
||||||
@EXPORT = qw();
|
|
||||||
|
|
||||||
sub initialize {
|
|
||||||
my $self = shift;
|
|
||||||
my %options = @_;
|
|
||||||
|
|
||||||
$self->{options}{'keys'} = '';
|
|
||||||
$self->{options}{'paths'} = '';
|
|
||||||
$self->{options}{'debug'} = 0;
|
|
||||||
$self->{options}{'verbose'} = 1;
|
|
||||||
$self->{options}{'skip_array'} = 0;
|
|
||||||
|
|
||||||
foreach my $opt ( keys %options ) {
|
|
||||||
die wrap_mod( "po4a::yaml", dgettext( "po4a", "Unknown option: %s" ), $opt )
|
|
||||||
unless exists $self->{options}{$opt};
|
|
||||||
$self->{options}{$opt} = $options{$opt};
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{options}{keys} =~ s/^\s*//;
|
|
||||||
foreach my $attr ( split( /\s+/, $self->{options}{keys} ) ) {
|
|
||||||
$self->{keys}{ lc($attr) } = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{options}{paths} =~ s/^\s*//;
|
|
||||||
foreach my $attr ( split( /,/, $self->{options}{paths} ) ) {
|
|
||||||
$self->{paths}{ lc( $attr =~ s/^\s+|\s+$//gr ) } = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub read {
|
|
||||||
my ( $self, $filename, $refname ) = @_;
|
|
||||||
push @{ $self->{DOCPOD}{infile} }, $filename;
|
|
||||||
$self->Locale::Po4a::TransTractor::read( $filename, $refname );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub parse {
|
|
||||||
my $self = shift;
|
|
||||||
map { $self->parse_file($_) } @{ $self->{DOCPOD}{infile} };
|
|
||||||
}
|
|
||||||
|
|
||||||
sub parse_file {
|
|
||||||
my ( $self, $filename ) = @_;
|
|
||||||
my $yaml = YAML::Tiny->read($filename)
|
|
||||||
|| die "Couldn't read YAML file $filename : $!";
|
|
||||||
|
|
||||||
for my $i ( 0 .. $#{$yaml} ) {
|
|
||||||
&walk_yaml( $self, $yaml->[$i], "" );
|
|
||||||
}
|
|
||||||
$self->pushline( Encode::encode_utf8( $yaml->write_string() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub walk_yaml {
|
|
||||||
my $self = shift;
|
|
||||||
my $el = shift;
|
|
||||||
my $ctx = shift;
|
|
||||||
|
|
||||||
my ( $line, $reference ) = $self->shiftline();
|
|
||||||
$reference =~ s/:[0-9]+$/:0/;
|
|
||||||
|
|
||||||
if ( ref $el eq 'HASH' ) {
|
|
||||||
print STDERR "begin a hash\n" if $self->{'options'}{'debug'};
|
|
||||||
foreach my $key ( sort keys %$el ) {
|
|
||||||
if ( ref $el->{$key} ne ref "" ) {
|
|
||||||
&walk_yaml( $self, $el->{$key}, "$ctx $key" );
|
|
||||||
} else {
|
|
||||||
my $path = "$ctx $key" =~ s/^\s+|\s+$//gr;
|
|
||||||
print STDERR "working on path '$path'\n" if $self->{'options'}{'debug'};
|
|
||||||
my $keysdefined = $self->{options}{keys} ne "";
|
|
||||||
my $keymatches = exists $self->{keys}{ lc($key) };
|
|
||||||
my $pathsdefined = $self->{options}{paths} ne "";
|
|
||||||
my $pathmatches = exists $self->{paths}{ lc($path) };
|
|
||||||
next
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
( $keysdefined and $keymatches )
|
|
||||||
or ( $pathsdefined and $pathmatches )
|
|
||||||
or ( not $keysdefined and not $pathsdefined )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
print STDERR " * path survived check\n" if $self->{'options'}{'debug'};
|
|
||||||
my $trans = $self->translate(
|
|
||||||
Encode::encode_utf8( $el->{$key} ),
|
|
||||||
$reference,
|
|
||||||
"Hash Value:$ctx $key",
|
|
||||||
'wrap' => 0
|
|
||||||
);
|
|
||||||
$el->{$key} = Encode::decode_utf8($trans); # Save the translation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elsif ( ref $el eq 'ARRAY' ) {
|
|
||||||
print STDERR "begin an array\n" if $self->{'options'}{'debug'};
|
|
||||||
for my $i ( 0 .. $#{$el} ) {
|
|
||||||
if ( ref $el->[$i] ne ref "" ) {
|
|
||||||
&walk_yaml( $self, $el->[$i], "$ctx" );
|
|
||||||
} elsif ( !$self->{options}{skip_array} ) { # translate that element only if not asked to skip arrays
|
|
||||||
my $trans =
|
|
||||||
$self->translate( Encode::encode_utf8( $el->[$i] ), $reference, "Array Element:$ctx", 'wrap' => 0 );
|
|
||||||
$el->[$i] = Encode::decode_utf8($trans); # Save the translation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print STDERR "got a string - this is unexpected in yaml\n" if $self->{'options'}{'debug'};
|
|
||||||
my $trans = $self->translate( Encode::encode_utf8($$el), $reference, "String:$ctx", 'wrap' => 0 );
|
|
||||||
$$el = Encode::decode_utf8($trans); # Save the translation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# Module return value and documentation
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
1;
|
|
||||||
__END__
|
|
||||||
|
|
||||||
=encoding UTF-8
|
=encoding UTF-8
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
@ -163,7 +29,7 @@ These are this module's particular options:
|
||||||
=item B<keys>
|
=item B<keys>
|
||||||
|
|
||||||
Space-separated list of hash keys to process for extraction, all
|
Space-separated list of hash keys to process for extraction, all
|
||||||
other keys are skipped. Keys are matched with a case-insensitive match.
|
other keys are skipped. Keys are matched with a case-sensitive match.
|
||||||
If B<paths> and B<keys> are used together, values are included if they are
|
If B<paths> and B<keys> are used together, values are included if they are
|
||||||
matched by at least one of the options.
|
matched by at least one of the options.
|
||||||
Arrays values are always returned unless the B<skip_array> option is
|
Arrays values are always returned unless the B<skip_array> option is
|
||||||
|
@ -172,7 +38,7 @@ provided.
|
||||||
=item B<paths>
|
=item B<paths>
|
||||||
|
|
||||||
Comma-separated list of hash paths to process for extraction, all
|
Comma-separated list of hash paths to process for extraction, all
|
||||||
other paths are skipped. Paths are matched with a case-insensitive match.
|
other paths are skipped. Paths are matched with a case-sensitive match.
|
||||||
If B<paths> and B<keys> are used together, values are included if they are
|
If B<paths> and B<keys> are used together, values are included if they are
|
||||||
matched by at least one of the options.
|
matched by at least one of the options.
|
||||||
Arrays values are always returned unless the B<skip_array> option is
|
Arrays values are always returned unless the B<skip_array> option is
|
||||||
|
@ -195,8 +61,81 @@ L<Locale::Po4a::TransTractor(3pm)>, L<po4a(7)|po4a.7>
|
||||||
=head1 COPYRIGHT AND LICENSE
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
Copyright © 2017 Brian Exelbierd.
|
Copyright © 2017 Brian Exelbierd.
|
||||||
|
Copyright © 2022 Martin Quinson <mquinson#debian.org>.
|
||||||
|
|
||||||
This program is free software; you may redistribute it and/or modify it
|
This program is free software; you may redistribute it and/or modify it
|
||||||
under the terms of GPL (see the COPYING file).
|
under the terms of GPL (see the COPYING file).
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# Modules and declarations
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
package Locale::Po4a::Yaml;
|
||||||
|
|
||||||
|
use Locale::Po4a::TransTractor;
|
||||||
|
use Locale::Po4a::Common;
|
||||||
|
use YAML::Tiny;
|
||||||
|
use Scalar::Util;
|
||||||
|
use Encode;
|
||||||
|
|
||||||
|
use 5.006;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
require Exporter;
|
||||||
|
|
||||||
|
use vars qw(@ISA @EXPORT $AUTOLOAD);
|
||||||
|
@ISA = qw(Locale::Po4a::TransTractor);
|
||||||
|
@EXPORT = qw();
|
||||||
|
|
||||||
|
my %yfm_keys = ();
|
||||||
|
my %yfm_paths = ();
|
||||||
|
|
||||||
|
sub initialize {
|
||||||
|
my $self = shift;
|
||||||
|
my %options = @_;
|
||||||
|
|
||||||
|
$self->{options}{'keys'} = '';
|
||||||
|
$self->{options}{'paths'} = '';
|
||||||
|
$self->{options}{'debug'} = 0;
|
||||||
|
$self->{options}{'verbose'} = 1;
|
||||||
|
$self->{options}{'skip_array'} = 0;
|
||||||
|
|
||||||
|
foreach my $opt ( keys %options ) {
|
||||||
|
die wrap_mod( "po4a::yaml", dgettext( "po4a", "Unknown option: %s" ), $opt )
|
||||||
|
unless exists $self->{options}{$opt};
|
||||||
|
$self->{options}{$opt} = $options{$opt};
|
||||||
|
}
|
||||||
|
|
||||||
|
map {
|
||||||
|
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||||
|
$yfm_keys{$_} = 1
|
||||||
|
} ( split( /[, ]/, $self->{options}{keys} ) );
|
||||||
|
# map { print STDERR "key: '$_'\n"; } (keys %yfm_keys);
|
||||||
|
|
||||||
|
map {
|
||||||
|
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||||
|
$yfm_paths{$_} = 1
|
||||||
|
} ( split( /,/, $self->{options}{paths} ));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub parse {
|
||||||
|
my $self = shift;
|
||||||
|
my $yfm;
|
||||||
|
my ( $nextline, $ref ) = $self->shiftline();
|
||||||
|
while ( defined($nextline) ) {
|
||||||
|
$yfm .= $nextline;
|
||||||
|
my $nextref;
|
||||||
|
( $nextline, $nextref ) = $self->shiftline();
|
||||||
|
}
|
||||||
|
|
||||||
|
my $yamlarray = YAML::Tiny->read_string($yfm)
|
||||||
|
|| die "YAML::Tiny failed to parse the content of $ref: $!";
|
||||||
|
|
||||||
|
$self->handle_yaml( 0, $ref, $yamlarray, \%yfm_keys, $self->{options}{skip_array}, \%yfm_paths );
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
|
@ -196,7 +196,7 @@ my $msgmergeOpts = ($noprevious ? "" : "--previous");
|
||||||
# Get all po files and report differences in them
|
# Get all po files and report differences in them
|
||||||
my ($pofile);
|
my ($pofile);
|
||||||
(undef,$pofile)=File::Temp::tempfile("po4aXXXX",
|
(undef,$pofile)=File::Temp::tempfile("po4aXXXX",
|
||||||
DIR => "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
SUFFIX => ".po",
|
SUFFIX => ".po",
|
||||||
OPEN => 0,
|
OPEN => 0,
|
||||||
UNLINK => 0)
|
UNLINK => 0)
|
||||||
|
|
542
po/bin/ace.po
542
po/bin/ace.po
File diff suppressed because it is too large
Load Diff
542
po/bin/af.po
542
po/bin/af.po
File diff suppressed because it is too large
Load Diff
542
po/bin/ar.po
542
po/bin/ar.po
File diff suppressed because it is too large
Load Diff
609
po/bin/ca.po
609
po/bin/ca.po
File diff suppressed because it is too large
Load Diff
605
po/bin/cs.po
605
po/bin/cs.po
File diff suppressed because it is too large
Load Diff
672
po/bin/de.po
672
po/bin/de.po
File diff suppressed because it is too large
Load Diff
666
po/bin/eo.po
666
po/bin/eo.po
File diff suppressed because it is too large
Load Diff
681
po/bin/es.po
681
po/bin/es.po
File diff suppressed because it is too large
Load Diff
621
po/bin/et.po
621
po/bin/et.po
File diff suppressed because it is too large
Load Diff
609
po/bin/eu.po
609
po/bin/eu.po
File diff suppressed because it is too large
Load Diff
711
po/bin/fr.po
711
po/bin/fr.po
File diff suppressed because it is too large
Load Diff
627
po/bin/hr.po
627
po/bin/hr.po
File diff suppressed because it is too large
Load Diff
631
po/bin/hu.po
631
po/bin/hu.po
File diff suppressed because it is too large
Load Diff
615
po/bin/id.po
615
po/bin/id.po
File diff suppressed because it is too large
Load Diff
668
po/bin/it.po
668
po/bin/it.po
File diff suppressed because it is too large
Load Diff
624
po/bin/ja.po
624
po/bin/ja.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
548
po/bin/kn.po
548
po/bin/kn.po
File diff suppressed because it is too large
Load Diff
542
po/bin/ko.po
542
po/bin/ko.po
File diff suppressed because it is too large
Load Diff
685
po/bin/nb.po
685
po/bin/nb.po
File diff suppressed because it is too large
Load Diff
697
po/bin/nl.po
697
po/bin/nl.po
File diff suppressed because it is too large
Load Diff
625
po/bin/pl.po
625
po/bin/pl.po
File diff suppressed because it is too large
Load Diff
544
po/bin/po4a.pot
544
po/bin/po4a.pot
File diff suppressed because it is too large
Load Diff
728
po/bin/pt.po
728
po/bin/pt.po
File diff suppressed because it is too large
Load Diff
690
po/bin/pt_BR.po
690
po/bin/pt_BR.po
File diff suppressed because it is too large
Load Diff
632
po/bin/ru.po
632
po/bin/ru.po
File diff suppressed because it is too large
Load Diff
609
po/bin/sl.po
609
po/bin/sl.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
625
po/bin/sv.po
625
po/bin/sv.po
File diff suppressed because it is too large
Load Diff
702
po/bin/uk.po
702
po/bin/uk.po
File diff suppressed because it is too large
Load Diff
701
po/bin/vi.po
701
po/bin/vi.po
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<!-- This file allows to automatically download the translations from the zanata servers -->
|
||||||
|
<!-- for n in ??.po ; do zanata po pull --lang basename $n .po ; done -->
|
||||||
|
|
||||||
|
<config xmlns="http://zanata.org/namespace/config/">
|
||||||
|
<url>https://translate.zanata.org/</url>
|
||||||
|
<project>po4a</project>
|
||||||
|
<project-version>bin</project-version>
|
||||||
|
<project-type>gettext</project-type>
|
||||||
|
</config>
|
646
po/bin/zh_CN.po
646
po/bin/zh_CN.po
File diff suppressed because it is too large
Load Diff
542
po/bin/zh_HK.po
542
po/bin/zh_HK.po
File diff suppressed because it is too large
Load Diff
1147
po/bin/zh_Hant.po
1147
po/bin/zh_Hant.po
File diff suppressed because it is too large
Load Diff
1948
po/pod/ca.po
1948
po/pod/ca.po
File diff suppressed because it is too large
Load Diff
2803
po/pod/de.po
2803
po/pod/de.po
File diff suppressed because it is too large
Load Diff
1656
po/pod/eo.po
1656
po/pod/eo.po
File diff suppressed because it is too large
Load Diff
3366
po/pod/es.po
3366
po/pod/es.po
File diff suppressed because it is too large
Load Diff
3163
po/pod/fr.po
3163
po/pod/fr.po
File diff suppressed because it is too large
Load Diff
1666
po/pod/hr.po
1666
po/pod/hr.po
File diff suppressed because it is too large
Load Diff
1656
po/pod/hu.po
1656
po/pod/hu.po
File diff suppressed because it is too large
Load Diff
2317
po/pod/it.po
2317
po/pod/it.po
File diff suppressed because it is too large
Load Diff
4500
po/pod/ja.po
4500
po/pod/ja.po
File diff suppressed because it is too large
Load Diff
1748
po/pod/nb.po
1748
po/pod/nb.po
File diff suppressed because it is too large
Load Diff
2777
po/pod/nl.po
2777
po/pod/nl.po
File diff suppressed because it is too large
Load Diff
2185
po/pod/pl.po
2185
po/pod/pl.po
File diff suppressed because it is too large
Load Diff
1672
po/pod/po4a-pod.pot
1672
po/pod/po4a-pod.pot
File diff suppressed because it is too large
Load Diff
3040
po/pod/pt.po
3040
po/pod/pt.po
File diff suppressed because it is too large
Load Diff
2643
po/pod/pt_BR.po
2643
po/pod/pt_BR.po
File diff suppressed because it is too large
Load Diff
2458
po/pod/ru.po
2458
po/pod/ru.po
File diff suppressed because it is too large
Load Diff
2780
po/pod/sr_Cyrl.po
2780
po/pod/sr_Cyrl.po
File diff suppressed because it is too large
Load Diff
2667
po/pod/uk.po
2667
po/pod/uk.po
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<!-- This file allows to automatically download the translations from the zanata servers -->
|
||||||
|
<!-- for n in ??.po ; do zanata po pull --lang basename $n .po ; done -->
|
||||||
|
|
||||||
|
<config xmlns="http://zanata.org/namespace/config/">
|
||||||
|
<url>https://translate.zanata.org/</url>
|
||||||
|
<project>po4a</project>
|
||||||
|
<project-version>pod</project-version>
|
||||||
|
<project-type>gettext</project-type>
|
||||||
|
</config>
|
2761
po/pod/zh_CHS.po
2761
po/pod/zh_CHS.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
261
po4a
261
po4a
|
@ -27,43 +27,24 @@ it decouples the translation of content from its document structure.
|
||||||
Please refer to the page L<po4a(7)> for a gentle introduction to this
|
Please refer to the page L<po4a(7)> for a gentle introduction to this
|
||||||
project.
|
project.
|
||||||
|
|
||||||
When you run the B<po4a> program for the first time, with only a
|
Upon execution, B<po4a> parses all documentation files specified in its
|
||||||
configuration file and the documents to translate (called master
|
configuration file. It updates the PO files (containing the translation) to
|
||||||
documents), it produces a POT file (also called translation template)
|
reflect any change to the documentation, and produce a translated documentation
|
||||||
that contains all of the translatable strings in the document in a form
|
by injecting the content's translation (found in the PO files) into the
|
||||||
that eases the work of translators.
|
structure of the original master document.
|
||||||
|
|
||||||
Those POT files can either be translated with a specific editor such
|
|
||||||
as the B<GNOME Translation Editor>, KDE's B<Lokalize> or B<poedit>,
|
|
||||||
or they can be integrated in an online localization platform such as
|
|
||||||
B<weblate> or B<pootle>. The translation result is a set of PO files,
|
|
||||||
one per language.
|
|
||||||
|
|
||||||
When you run the B<po4a> program with both the master documents and
|
|
||||||
the PO files, it produces the translated documents by injecting the
|
|
||||||
content's translation (found in the PO files) into the structure of
|
|
||||||
the original master document.
|
|
||||||
|
|
||||||
If the master documents changed in the meanwhile, po4a will update the PO
|
|
||||||
and POT files accordingly, so that the translators can easily detect the
|
|
||||||
modifications and update their work. Depending on your settings, po4a will
|
|
||||||
discard the partially translated documents, or produce a document mixing
|
|
||||||
English (for the new or modified paragraphs) and the target language
|
|
||||||
(for paragraphs where translation is already in the PO file).
|
|
||||||
|
|
||||||
By default, the translated documents are produced when at least 80%
|
|
||||||
of their content is translated (see the I<--keep> option below).
|
|
||||||
Discarding translations as soon as they are not 100% may be
|
|
||||||
discouraging for the translators, while showing "translations" that
|
|
||||||
are too incomplete may be troubling for the end users.
|
|
||||||
|
|
||||||
=head2 Graphical overview
|
|
||||||
|
|
||||||
|
At first, the PO files only contain the strings to translate from the original
|
||||||
|
documentation. This file format allows the translators to manually provide a
|
||||||
|
translation for each paragraph extracted by B<po4a>. If the documentation is
|
||||||
|
modified after translation, B<po4a> marks the corresponding translations as
|
||||||
|
"fuzzy" in the PO file to request a manual review by the translators. The
|
||||||
|
translators can also provide so-called "addendum", that are extra content
|
||||||
|
stating for example who did the translation and how to report bugs.
|
||||||
|
|
||||||
master documents ---+---->-------->---------+
|
master documents ---+---->-------->---------+
|
||||||
(doc authoring) | |
|
(doc authoring) | |
|
||||||
V (po4a executions) >-----+--> translations
|
V (po4a executions) >-----+--> translated
|
||||||
| | |
|
| | | documents
|
||||||
existing PO files -->--> updated PO files >-+ |
|
existing PO files -->--> updated PO files >-+ |
|
||||||
^ | |
|
^ | |
|
||||||
| V |
|
| V |
|
||||||
|
@ -72,13 +53,100 @@ are too incomplete may be troubling for the end users.
|
||||||
|
|
|
|
||||||
addendum -->--------------------------------------+
|
addendum -->--------------------------------------+
|
||||||
|
|
||||||
The master documents are authored by the documentation writers. Any changes are
|
The workflow of B<po4a> is asynchronous, as suited to open-source projects. The
|
||||||
automatically reflected by po4a in the PO files, that are then updated by the
|
documentation writers author the master documents at their own pace. The
|
||||||
translators. All changes to the PO files (either manual or by po4a) are
|
translators review and update the translations in the PO files. The maintainers
|
||||||
automatically reflected in translated documents. You can mimic this behavior
|
rerun B<po4a> on need, to reflect any change to the original documentation to
|
||||||
using the L<po4a-updatepo(1)> and L<po4a-translate(1)> scripts in makefiles, but
|
the PO files, and to produce updated documentation translations, by injecting
|
||||||
this quickly becomes bothersome and repetitive (see L<po4a(7)>). It is highly
|
the latest translation into the latest document structure.
|
||||||
recommended to use the B<po4a> program in your build process.
|
|
||||||
|
By default, a given translated document is produced when at least 80% of its
|
||||||
|
content is translated. The untranslated text is kept in the original language.
|
||||||
|
The produced documentation thus mixes languages if the translation is not
|
||||||
|
complete. You can change the 80% threshold with the I<--keep> option described
|
||||||
|
below. Note however that discarding translations as soon as they are not 100%
|
||||||
|
may be discouraging for the translators whose work will almost never be shown to
|
||||||
|
the users, while showing "translations" that are too incomplete may be troubling
|
||||||
|
for the end users.
|
||||||
|
|
||||||
|
Storing the translated documentation files in the version control system is
|
||||||
|
probably a bad idea, since they are automatically generated. The precious files
|
||||||
|
are the PO files, that contain the hard work of your fellow translators. Also,
|
||||||
|
some people find it easier to interact with the translators through an online
|
||||||
|
platform such as S<weblate>, but this is naturally fully optional.
|
||||||
|
|
||||||
|
=head2 Quick start tutorial
|
||||||
|
|
||||||
|
Let's assume you maintain a program named B<foo> which has a man page
|
||||||
|
F<man/foo.1> written in English (the bridge language in most open-source
|
||||||
|
projects, but B<po4a> can be used from or to any language). Some times ago,
|
||||||
|
someone provided a German translation named F<man/foo.de.1> and disappeared.
|
||||||
|
This is a problem because you just got a bug report saying that your
|
||||||
|
documentation contains a gravely misleading information that must be fixed in
|
||||||
|
all languages, but you don't speak German so you can only modify the original,
|
||||||
|
not the translation. Now, another contributor wants to contribute a translation
|
||||||
|
to Japanese, a language that you don't master either.
|
||||||
|
|
||||||
|
It is time to convert your documentation to B<po4a> to solve your documentation
|
||||||
|
maintenance nightmares. You want to update the doc when needed, you want to ease
|
||||||
|
the work of your fellow translators, and you want to ensure that your users
|
||||||
|
never see any outdated and thus misleading documentation.
|
||||||
|
|
||||||
|
The conversion includes two steps: setup the po4a infrastructure, and convert
|
||||||
|
the previous German translation to salvage the previous work. This latter part
|
||||||
|
is done using S<po4a-gettextize>, as follows. As detailed in the documentation
|
||||||
|
of L<po4a-gettextize(1)>, this process rarely fully automatic, but once it's
|
||||||
|
done, the B<de.po> file containing the German translation can be integrated in
|
||||||
|
your po4a workflow.
|
||||||
|
|
||||||
|
po4a-gettextize --format man --master foo.1 --localized foo.de.1 --po de.po
|
||||||
|
|
||||||
|
Let's now configure po4a. With the appropriate file layout, your configuration
|
||||||
|
file could be as simple as this:
|
||||||
|
|
||||||
|
[po_directory] man/po4a/
|
||||||
|
|
||||||
|
[type: man] man/foo.1 $lang:man/translated/foo.$lang.1
|
||||||
|
|
||||||
|
It specifies that all PO files (containing the work of the translators) are the
|
||||||
|
F<man/po4a/> directory, and that you have only one master file, F<man/foo.1>. If
|
||||||
|
you had several master files, you would have several lines similar to the second
|
||||||
|
one. Each such line also specify where to write the corresponding translation
|
||||||
|
files. Here, the German translation of F<man/foo.1> is in
|
||||||
|
F<man/translated/foo.de.1>.
|
||||||
|
|
||||||
|
The last thing we need to complete the configuration of B<po4a> is a POT file
|
||||||
|
containing the template material that should be used to start a new translation.
|
||||||
|
Simply create an empty file with the S<.pot> extension in the specified
|
||||||
|
S<po_directory> (e.g. F<man/po4a/foo.pot>), and B<po4a> will fill it with the
|
||||||
|
expected content.
|
||||||
|
|
||||||
|
Here is a recap of the files in this setup:
|
||||||
|
|
||||||
|
├── man/
|
||||||
|
│ ├── foo.1 <- The original man page, in English.
|
||||||
|
│ ├── po4a/
|
||||||
|
│ │ ├── de.po <- The German PO translation, from gettextization.
|
||||||
|
│ │ └── foo.pot <- The POT template of future translations (empty at first)
|
||||||
|
│ └── translated/ <- Directory where the translations will be created
|
||||||
|
└── po4a.cfg <- The configuration file.
|
||||||
|
|
||||||
|
Once setup, executing B<po4a> will parse your documentation, update the POT
|
||||||
|
template file, use it to update the PO translation files, and use them to update
|
||||||
|
the documentation translation files. All in one command:
|
||||||
|
|
||||||
|
po4a --verbose po4a.cfg
|
||||||
|
|
||||||
|
This it. B<po4a> is now fully configured. Once you've fixed your error in
|
||||||
|
F<man/foo.1>, the offending paragraph in the German translation will be replaced by
|
||||||
|
the fixed text in English. Mixing languages is not optimal, but it's the only
|
||||||
|
way to remove errors in translations that you don't even understand, and ensure
|
||||||
|
that the content presented to the users is never misleading. Updating the German
|
||||||
|
translation is also much easier in the corresponding PO file, so the language
|
||||||
|
mix-up may not last long. Finally, when the Japanese translator gives you a
|
||||||
|
S<jp.po> translated file, just drop it in F<man/po4a/po/>. A translated page
|
||||||
|
will appear as F<man/translated/foo.jp.1> (provided that enough content is
|
||||||
|
translated) when you run B<po4a> again.
|
||||||
|
|
||||||
=head1 OPTIONS
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
@ -259,7 +327,7 @@ content. If set to B<newlines>, po4a will only split the msgid and msgstr after
|
||||||
newlines in the content. If set to B<no>, po4a will not wrap the po file at all.
|
newlines in the content. If set to B<no>, po4a will not wrap the po file at all.
|
||||||
The reference comments are always wrapped by the gettext tools that we use internally.
|
The reference comments are always wrapped by the gettext tools that we use internally.
|
||||||
|
|
||||||
Note that this option has no impact on how the msgid and msgstr are wrapped, ie
|
Note that this option has no impact on how the msgid and msgstr are wrapped, i.e.
|
||||||
on how newlines are added to the content of these strings.
|
on how newlines are added to the content of these strings.
|
||||||
|
|
||||||
=item B<--master-language>
|
=item B<--master-language>
|
||||||
|
@ -300,7 +368,7 @@ Note: B<$lang> will be extended to the current language.
|
||||||
=item B<--no-previous>
|
=item B<--no-previous>
|
||||||
|
|
||||||
This option removes B<--previous> from the options passed to B<msgmerge>.
|
This option removes B<--previous> from the options passed to B<msgmerge>.
|
||||||
This permits to support versions of B<gettext> earlier than 0.16.
|
This is necessary to support versions of B<gettext> earlier than 0.16.
|
||||||
|
|
||||||
=item B<--previous>
|
=item B<--previous>
|
||||||
|
|
||||||
|
@ -387,16 +455,20 @@ C<$master> in the name of your PO files on the C<[po4a_paths]> line, as follows.
|
||||||
|
|
||||||
[po4a_paths] doc/$master/$master.pot $lang:doc/$master/$lang.po
|
[po4a_paths] doc/$master/$master.pot $lang:doc/$master/$lang.po
|
||||||
|
|
||||||
With this line, po4a will produce separate POT and PO files for each document to translate.
|
With this line, po4a will produce separate POT and PO files for each document to translate.
|
||||||
For example, if you have 3 documents and 5 languages, this will result in 3 POT files and
|
For example, if you have 3 documents and 5 languages, this will result in 3 POT files and
|
||||||
15 PO files. These files are named as specified on the C<po4a_paths> template, with
|
15 PO files. These files are named as specified on the C<po4a_paths> template, with
|
||||||
C<$master> substituted to the basename of each document to translate. In case of name
|
C<$master> substituted to the basename of each document to translate. In case of name
|
||||||
conflict, you can specify the POT file to use as follows, with the C<pot=> parameter.
|
conflict, you can specify the POT file to use as follows, with the C<pot=> parameter.
|
||||||
This feature can also be used to group several translated files into the same POT file.
|
|
||||||
|
This feature can also be used to group several translated files into the same
|
||||||
|
POT file. The following example only produces 2 POT files: F<l10n/po/foo.pot>
|
||||||
|
(containing the material from F<foo/gui.xml>) and F<l10n/po/bar.pot> (containing
|
||||||
|
the material from both F<bar/gui.xml> and F<bar/cli.xml>).
|
||||||
|
|
||||||
[po4a_langs] de fr ja
|
[po4a_langs] de fr ja
|
||||||
[po4a_paths] l10n/po/$master.pot $lang:l10n/po/$master.$lang.po
|
[po4a_paths] l10n/po/$master.pot $lang:l10n/po/$master.$lang.po
|
||||||
[type: xml] foo/gui.xml $lang:foo/gui.$lang.xml pot=foo-gui
|
[type: xml] foo/gui.xml $lang:foo/gui.$lang.xml pot=foo
|
||||||
[type: xml] bar/gui.xml $lang:bar/gui.$lang.xml pot=bar
|
[type: xml] bar/gui.xml $lang:bar/gui.$lang.xml pot=bar
|
||||||
[type: xml] bar/cli.xml $lang:bar/cli.$lang.xml pot=bar
|
[type: xml] bar/cli.xml $lang:bar/cli.$lang.xml pot=bar
|
||||||
|
|
||||||
|
@ -404,7 +476,7 @@ In split mode, B<po4a> builds a temporary compendium during the PO update, to
|
||||||
share the translations between all the PO files. If two PO files have different
|
share the translations between all the PO files. If two PO files have different
|
||||||
translations for the same string, B<po4a> will mark this string as fuzzy and
|
translations for the same string, B<po4a> will mark this string as fuzzy and
|
||||||
will submit both translations in all the PO files containing this string. When
|
will submit both translations in all the PO files containing this string. When
|
||||||
unfuzzied by the translator, the translation is automatically used in every PO
|
unfuzzied by the translator, the translation is automatically used in every PO
|
||||||
files.
|
files.
|
||||||
|
|
||||||
=head2 Specifying the documents to translate
|
=head2 Specifying the documents to translate
|
||||||
|
@ -599,78 +671,20 @@ these strings will be left unmodified when producing the translated documents.
|
||||||
This naturally decreases the level of translation, so you may need the C<--keep>
|
This naturally decreases the level of translation, so you may need the C<--keep>
|
||||||
option to ensure that the document is produced anyway.
|
option to ensure that the document is produced anyway.
|
||||||
|
|
||||||
=head2 CONFIGURATION EXAMPLE
|
|
||||||
|
|
||||||
TODO: Is this section really useful?
|
|
||||||
|
|
||||||
Let's assume you maintain a program named B<foo> which has a man page F<man/foo.1>
|
|
||||||
which naturally is maintained in English only. Now you as the upstream or
|
|
||||||
downstream maintainer want to create and maintain the translation.
|
|
||||||
First you need to create the POT file necessary to send to translators
|
|
||||||
using L<po4a-gettextize(1)>.
|
|
||||||
|
|
||||||
So for our case we would call
|
|
||||||
|
|
||||||
cd man && po4a-gettextize -f man -m foo.1 -p foo.pot
|
|
||||||
|
|
||||||
You would then send this file to the appropriate language lists or offer
|
|
||||||
it for download somewhere on your website.
|
|
||||||
|
|
||||||
Now let's assume you received three translations before your next release:
|
|
||||||
F<de.po> (including an addendum F<de.add>), F<sv.po> and F<pt.po>.
|
|
||||||
Since you don't want to change your F<Makefile>(s) whenever a new translation
|
|
||||||
arrives you can use B<po4a> with an appropriate configuration file in your F<Makefile>.
|
|
||||||
Let's call it F<po4a.cfg>. In our example it would look like the following:
|
|
||||||
|
|
||||||
[po_directory] man/po4a/po/
|
|
||||||
|
|
||||||
[type: man] man/foo.1 $lang:man/translated/$lang/foo.1 \
|
|
||||||
add_$lang:?man/po4a/add_$lang/$lang.add opt:"-k 80"
|
|
||||||
|
|
||||||
In this example we assume that your generated man pages (and all PO and addenda
|
|
||||||
files) should be stored in F<man/translated/$lang/> (respectively in F<man/po4a/po/> and
|
|
||||||
F<man/po4a/add_$lang/>) below the current directory. In our example
|
|
||||||
the F<man/po4a/po/> directory would include F<de.po>, F<pt.po> and F<sv.po>,
|
|
||||||
and the F<man/po4a/add_de/> directory would include F<de.add>.
|
|
||||||
|
|
||||||
Note the use of the modifier B<?> as only the German translation (F<de.po>) is
|
|
||||||
accompanied by an addendum.
|
|
||||||
|
|
||||||
To actually build the translated man pages you would then (once!) add the
|
|
||||||
following line in the B<build> target of the appropriate F<Makefile>:
|
|
||||||
|
|
||||||
po4a po4a.cfg
|
|
||||||
|
|
||||||
Once this is set up you don't need to touch the F<Makefile> when a new
|
|
||||||
translation arrives, i.e. if the French team sends you F<fr.po> and F<fr.add>
|
|
||||||
then you simply drop them respectively in F<man/po4a/po/> and
|
|
||||||
F<man/po4a/add_fr/> and the next time the program is built the
|
|
||||||
French translation is automatically build as well in F<man/translated/fr/>.
|
|
||||||
|
|
||||||
Note that you still need an appropriate target to install localized manual
|
|
||||||
pages with English ones.
|
|
||||||
|
|
||||||
Finally if you do not store generated files into your version control system,
|
|
||||||
you will need a line in your B<clean> target as well:
|
|
||||||
-rm -rf man/translated
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
L<po4a-gettextize(1)>,
|
L<po4a-gettextize(1)>,
|
||||||
L<po4a-normalize(1)>,
|
|
||||||
L<po4a-translate(1)>,
|
|
||||||
L<po4a-updatepo(1)>,
|
|
||||||
L<po4a(7)>.
|
L<po4a(7)>.
|
||||||
|
|
||||||
=head1 AUTHORS
|
=head1 AUTHORS
|
||||||
|
|
||||||
Denis Barbier <barbier@linuxfr.org>
|
Denis Barbier <barbier@linuxfr.org>
|
||||||
Nicolas Francois <nicolas.francois@centraliens.net>
|
Nicolas François <nicolas.francois@centraliens.net>
|
||||||
Martin Quinson (mquinson#debian.org)
|
Martin Quinson (mquinson#debian.org)
|
||||||
|
|
||||||
=head1 COPYRIGHT AND LICENSE
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
Copyright 2002-2020 by SPI, inc.
|
Copyright 2002-2022 by SPI, inc.
|
||||||
|
|
||||||
This program is free software; you may redistribute it and/or modify it
|
This program is free software; you may redistribute it and/or modify it
|
||||||
under the terms of GPL (see the COPYING file).
|
under the terms of GPL (see the COPYING file).
|
||||||
|
@ -1119,15 +1133,16 @@ while (<CONFIG>) {
|
||||||
next unless defined $basedir;
|
next unless defined $basedir;
|
||||||
my $candidate = "$basedir/$po_directory";
|
my $candidate = "$basedir/$po_directory";
|
||||||
if ( -e $candidate && -d $candidate ) {
|
if ( -e $candidate && -d $candidate ) {
|
||||||
$found = 1;
|
|
||||||
print STDERR wrap_msg( gettext("Using '%s' as a %s."), $candidate, "po_directory" )
|
|
||||||
if $po4a_opts{"verbose"};
|
|
||||||
|
|
||||||
opendir PO_DIR,
|
opendir PO_DIR,
|
||||||
$candidate
|
$candidate
|
||||||
or die wrap_ref_mod( "$config_file:$nb", "", gettext("Cannot list directory '%s' in '%s' "),
|
or die wrap_ref_mod( "$config_file:$nb", "", gettext("Cannot list directory '%s' in '%s' "),
|
||||||
$po_directory, $basedir );
|
$po_directory, $basedir );
|
||||||
map { push @po_files, "$po_directory/$_" if -e "$candidate/$_"; } ( sort readdir PO_DIR );
|
map { push @po_files, "$po_directory/$_" if -e "$candidate/$_"; } ( sort readdir PO_DIR );
|
||||||
|
|
||||||
|
# Only display the message the first time we find the right directory
|
||||||
|
print STDERR wrap_msg( gettext("Using '%s' as a %s."), $candidate, "po_directory" )
|
||||||
|
if $po4a_opts{"verbose"} && $found == 0 && scalar @po_files;
|
||||||
|
$found = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unless ($found) {
|
unless ($found) {
|
||||||
|
@ -1431,7 +1446,12 @@ if ( $pot_filename =~ m/\$master/ ) {
|
||||||
|
|
||||||
if ( not scalar @{ $po4a_opts{"partial"} } ) {
|
if ( not scalar @{ $po4a_opts{"partial"} } ) {
|
||||||
if ( -e find_input_file($pot_filename) ) {
|
if ( -e find_input_file($pot_filename) ) {
|
||||||
my $modtime = ( stat find_input_file($pot_filename) )[9];
|
my @statfile = stat find_input_file($pot_filename);
|
||||||
|
my $filesize = $statfile[7];
|
||||||
|
my $modtime = $statfile[9];
|
||||||
|
|
||||||
|
# The POT files needs to be generated if it's currently empty (first run?)
|
||||||
|
$update_pot_file = 1 if $filesize == 0;
|
||||||
|
|
||||||
# The POT needs to be re-generated if a master document is more recent
|
# The POT needs to be re-generated if a master document is more recent
|
||||||
# than the POT.
|
# than the POT.
|
||||||
|
@ -1535,7 +1555,7 @@ if ($update_pot_file) {
|
||||||
if ( $po4a_opts{"split"} ) {
|
if ( $po4a_opts{"split"} ) {
|
||||||
( undef, $pot_filename ) = File::Temp::tempfile(
|
( undef, $pot_filename ) = File::Temp::tempfile(
|
||||||
"po4a-temp-pot-XXXX",
|
"po4a-temp-pot-XXXX",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
SUFFIX => ".pot",
|
SUFFIX => ".pot",
|
||||||
OPEN => 0,
|
OPEN => 0,
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
|
@ -1583,7 +1603,7 @@ if ( $po4a_opts{"split"} ) {
|
||||||
unless ( $po4a_opts{"force"} ) {
|
unless ( $po4a_opts{"force"} ) {
|
||||||
( undef, $tmp_file ) = File::Temp::tempfile(
|
( undef, $tmp_file ) = File::Temp::tempfile(
|
||||||
"po4aXXXX",
|
"po4aXXXX",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
SUFFIX => ".pot",
|
SUFFIX => ".pot",
|
||||||
OPEN => 0,
|
OPEN => 0,
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
|
@ -1616,7 +1636,7 @@ if ( $po4a_opts{"split"} ) {
|
||||||
my $tmp_bigpo;
|
my $tmp_bigpo;
|
||||||
( undef, $tmp_bigpo ) = File::Temp::tempfile(
|
( undef, $tmp_bigpo ) = File::Temp::tempfile(
|
||||||
"po4aXXXX",
|
"po4aXXXX",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
SUFFIX => "-$lang.po",
|
SUFFIX => "-$lang.po",
|
||||||
OPEN => 0,
|
OPEN => 0,
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
|
@ -1705,7 +1725,7 @@ if ( not $po4a_opts{"no-update"} ) {
|
||||||
# updated (unless --force was specified).
|
# updated (unless --force was specified).
|
||||||
( undef, $tmp_file ) = File::Temp::tempfile(
|
( undef, $tmp_file ) = File::Temp::tempfile(
|
||||||
"po4aXXXX",
|
"po4aXXXX",
|
||||||
DIR => $ENV{TMPDIR} || "/tmp",
|
DIR => File::Spec->tmpdir(),
|
||||||
SUFFIX => ".po",
|
SUFFIX => ".po",
|
||||||
OPEN => 0,
|
OPEN => 0,
|
||||||
UNLINK => 0
|
UNLINK => 0
|
||||||
|
@ -1990,3 +2010,6 @@ sub is_older {
|
||||||
}
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
|
# LocalWords: Charset charset AsciiDoc tablecells po UTF gettext msgid nostrip
|
||||||
|
# LocalWords: xml docbook
|
||||||
|
|
485
po4a-gettextize
485
po4a-gettextize
|
@ -17,7 +17,7 @@ po4a-gettextize - convert an original file (and its translation) to a PO file
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
B<po4a-gettextize> B<-f> I<fmt> B<-m> I<master.doc> [B<-l> I<XX.doc>] B<-p> I<XX.po>
|
B<po4a-gettextize> B<-f> I<fmt> B<-m> I<master.doc> B<-l> I<XX.doc> B<-p> I<XX.po>
|
||||||
|
|
||||||
(I<XX.po> is the output, all others are inputs)
|
(I<XX.po> is the output, all others are inputs)
|
||||||
|
|
||||||
|
@ -28,20 +28,21 @@ the classical gettext tools. The main feature of po4a is that it decouples the
|
||||||
translation of content from its document structure. Please refer to the page
|
translation of content from its document structure. Please refer to the page
|
||||||
L<po4a(7)> for a gentle introduction to this project.
|
L<po4a(7)> for a gentle introduction to this project.
|
||||||
|
|
||||||
The B<po4a-gettextize> script is in charge of converting documentation files into
|
The B<po4a-gettextize> script helps you converting your previously existing
|
||||||
PO files. You only need it to setup your translation project with po4a, never afterward.
|
translations into a po4a-based workflow. This is only to be done once to salvage
|
||||||
|
an existing translation while converting to po4a, not on a regular basis after
|
||||||
|
the conversion of your project. This tedious process is explained in details in
|
||||||
|
Section 'Converting a manual translation to po4a' below.
|
||||||
|
|
||||||
If you start from scratch, B<po4a-gettextize> will extract the translatable
|
You must provide both a master file (e.g., the source in English) and an
|
||||||
strings from the documentation and write a POT file. If you provide a previously
|
existing translated file (e.g., a previous translation attempt without po4a). If
|
||||||
existing translated file with the B<-l> flag, B<po4a-gettextize> will try to use
|
you provide more than one master or translation files, they will be used in
|
||||||
the translations that it contains in the produced PO file. This process remains
|
sequence, but it may be easier to gettextize each page or chapter separately and
|
||||||
tedious and manual, as explained in Section 'Converting a manual translation to
|
then use B<msgmerge> to merge all produced PO files. As you wish.
|
||||||
po4a' below.
|
|
||||||
|
|
||||||
If the master document has non-ASCII characters, the new generated PO file will
|
If the master document has non-ASCII characters, the new generated PO file will
|
||||||
be in UTF-8. Else (if the master document is completely in ASCII), the generated
|
be in UTF-8. If the master document is completely in ASCII, the generated
|
||||||
PO will use the encoding of the translated input document, or UTF-8 if no
|
PO will use the encoding of the translated input document.
|
||||||
translated document is provided.
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
@ -79,8 +80,8 @@ catalog will be written to the standard output.
|
||||||
=item B<-o>, B<--option>
|
=item B<-o>, B<--option>
|
||||||
|
|
||||||
Extra option(s) to pass to the format plugin. See the documentation of each
|
Extra option(s) to pass to the format plugin. See the documentation of each
|
||||||
plugin for more information about the valid options and their meanings. For
|
plugin for more information about the valid options and their meanings. For
|
||||||
example, you could pass '-o tablecells' to the AsciiDoc parser, while the
|
example, you could pass '-o tablecells' to the AsciiDoc parser, while the
|
||||||
text parser would accept '-o tabs=split'.
|
text parser would accept '-o tabs=split'.
|
||||||
|
|
||||||
=item B<-h>, B<--help>
|
=item B<-h>, B<--help>
|
||||||
|
@ -91,6 +92,11 @@ Show a short help message.
|
||||||
|
|
||||||
List the documentation formats understood by po4a.
|
List the documentation formats understood by po4a.
|
||||||
|
|
||||||
|
=item B<-k> B<--keep-temps>
|
||||||
|
|
||||||
|
Keep the temporary master and localized POT files built before merging.
|
||||||
|
This can be useful to understand why these files get desynchronized, leading to gettextization problems
|
||||||
|
|
||||||
=item B<-V>, B<--version>
|
=item B<-V>, B<--version>
|
||||||
|
|
||||||
Display the version of the script and exit.
|
Display the version of the script and exit.
|
||||||
|
@ -125,19 +131,24 @@ Set the package version for the POT header. The default is "VERSION".
|
||||||
|
|
||||||
=head2 Converting a manual translation to po4a
|
=head2 Converting a manual translation to po4a
|
||||||
|
|
||||||
B<po4a-gettextize> will try to extract the content of any provided translation
|
B<po4a-gettextize> synchronizes the master and localized files to extract their
|
||||||
file, and use this content as msgstr in the produced PO file. Be warned that
|
content into a PO file. The content of the master file gives the B<msgid> while
|
||||||
this process is very fragile: the Nth string of the translated file is supposed
|
the content of the localized file gives the B<msgstr>. This process is somewhat
|
||||||
to be the translation of the Nth string in the original. This will naturally not
|
fragile: the Nth string of the translated file is supposed to be the translation
|
||||||
work unless both files share exactly the same structure.
|
of the Nth string in the original.
|
||||||
|
|
||||||
|
Gettextization works best if you manage to retrieve the exact version of the
|
||||||
|
original document that was used for translation. Even so, you may need to fiddle
|
||||||
|
with both master and localized files to align their structure if it was changed
|
||||||
|
by the original translator, so working on files' copies is advised.
|
||||||
|
|
||||||
Internally, each po4a parser reports the syntactical type of each extracted
|
Internally, each po4a parser reports the syntactical type of each extracted
|
||||||
strings. This is how desynchronization are detected during the gettextization.
|
strings. This is how desynchronization are detected during the gettextization.
|
||||||
For example, if the files have the following structure, it is very unlikely that
|
In the example depicted below, it is very unlikely that the 4th string in
|
||||||
the 4th string in translation (of type 'chapter') is the translation of the 4th
|
translation (of type 'chapter') is the translation of the 4th string in original
|
||||||
string in original (of type 'paragraph'). It is more likely that a new
|
(of type 'paragraph'). It is more likely that a new paragraph was added to the
|
||||||
paragraph was added to the original, or that two original paragraphs were merged
|
original, or that two original paragraphs were merged together in the
|
||||||
together in the translation.
|
translation.
|
||||||
|
|
||||||
Original Translation
|
Original Translation
|
||||||
|
|
||||||
|
@ -148,73 +159,57 @@ together in the translation.
|
||||||
chapter paragraph
|
chapter paragraph
|
||||||
paragraph paragraph
|
paragraph paragraph
|
||||||
|
|
||||||
B<po4a-gettextize> will verbosely diagnose any detected structure
|
B<po4a-gettextize> will verbosely diagnose any structure desynchronization. When
|
||||||
desynchronization. When this happens, you should manually edit the files (this
|
this happens, you should manually edit the files to add fake paragraphs or
|
||||||
probably requires that you have some notions of the target language). You must
|
remove some content here and there until the structure of both files actually
|
||||||
add fake paragraphs or remove some content in one of the documents (or both) to
|
match. Some tricks are given below to salvage the most of the existing
|
||||||
fix the reported disparities, until the structure of both documents perfectly
|
translation while doing so.
|
||||||
match. Some tricks are given in the next section.
|
|
||||||
|
|
||||||
Even when the document is successfully processed, undetected disparities and
|
If you are lucky enough to have a perfect match in the file structures out of
|
||||||
silent errors are still possible. That is why any translation associated
|
the box, building a correct PO file is a matter of seconds. Otherwise, you will
|
||||||
automatically by po4a-gettextize is marked as I<fuzzy> to require an manual
|
soon understand why this process has such an ugly name :) Even so,
|
||||||
inspection by humans. One has to check that each retrieved msgstr is actually
|
gettextization often remains faster than translating everything again. I
|
||||||
the translation of the associated msgid, and not the string before or after.
|
gettextized the French translation of the whole Perl documentation in one day
|
||||||
|
despite the I<many> synchronization issues. Given the amount of text (2Mb of
|
||||||
|
original text), restarting the translation without first salvaging the old
|
||||||
|
translations would have required several months of work. In addition, this grunt
|
||||||
|
work is the price to pay to get the comfort of po4a. Once converted, the
|
||||||
|
synchronization between master documents and translations will always be fully
|
||||||
|
automatic.
|
||||||
|
|
||||||
As you can see, the key here is to have the exact same structure in the
|
After a successful gettextization, the produced documents should be manually
|
||||||
translated document and in the original one. The best is to do the
|
checked for undetected disparities and silent errors, as explained below.
|
||||||
gettextization on the exact version of F<master.doc> that was used for the
|
|
||||||
translation, and only update the PO file against the latest master file once the
|
|
||||||
gettextization was successful.
|
|
||||||
|
|
||||||
If you are lucky enough to have a a perfect match in the file structures,
|
=head3 Hints and tricks for the gettextization process
|
||||||
building a correct PO file is a matter of seconds. Otherwise, you will soon
|
|
||||||
understand why this process has such an ugly name :) But remember that this
|
|
||||||
grunt work is the price to pay to get the comfort of po4a afterward. Once
|
|
||||||
converted, the synchronization between master documents and translations will
|
|
||||||
always be fully automatic.
|
|
||||||
|
|
||||||
Even when things go wrong, gettextization often remains faster than translating
|
The gettextization stops as soon as a desynchronization is detected. When this
|
||||||
everything again. I was able to gettextize the existing French translation of
|
happens, you need to edit the files as much as needed to re-align the files'
|
||||||
the whole Perl documentation in one day, even though the structure of many
|
structures. B<po4a-gettextize> is rather verbose when things go wrong. It
|
||||||
documents were desynchronized. That was more than two megabytes of original text
|
reports the strings that don't match, their positions in the text, and the type
|
||||||
(2 millions of characters): restarting the translation from scratch would have
|
of each of them. Moreover, the PO file generated so far is dumped as
|
||||||
required several months of work.
|
F<gettextization.failed.po> for further inspection.
|
||||||
|
|
||||||
=head2 Hints and tricks for the gettextization process
|
Here are some tricks to help you in this tedious process and ensure that you
|
||||||
|
salvage the most of the previous translation:
|
||||||
The gettextization stops as soon as a desynchronization is detected. In theory,
|
|
||||||
it should probably be possible resynchronize the gettextization later in the
|
|
||||||
documents using e.g. the same algorithm than the L<diff(1)> utility. But a manual
|
|
||||||
intervention would still be mandatory to manually match the elements that
|
|
||||||
couldn't be automatically matched, explaining why automatic resynchronization is
|
|
||||||
not implemented (yet?).
|
|
||||||
|
|
||||||
When this happens, the whole game comes down to the alignment of these damn
|
|
||||||
files' structures again through manual edits. B<po4a-gettextize> is rather
|
|
||||||
verbose about what went wrong when it happens. It reports the strings that don't
|
|
||||||
match, their positions in the text, and the type of each of them. Moreover, the
|
|
||||||
PO file generated so far is dumped as F<gettextization.failed.po> for further
|
|
||||||
inspection.
|
|
||||||
|
|
||||||
Here are some other tricks to help you in this tedious process:
|
|
||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
=item
|
=item
|
||||||
|
|
||||||
Remove all extra content of the translations, such as the section giving credits
|
Remove all extra content of the translations, such as the section giving credits
|
||||||
to the translators. You can add them back in po4a afterward, using an addenda
|
to the translators. They should be added separately to B<po4a> as addendas (see
|
||||||
(see L<po4a(7)>).
|
L<po4a(7)>).
|
||||||
|
|
||||||
=item
|
=item
|
||||||
|
|
||||||
If you need to edit the files to align their structures, you should prefer
|
When editing the files to align their structures, prefer editing the translation
|
||||||
editing the translation if possible. Indeed, if the changes to the original are
|
if possible. Indeed, if the changes to the original are too intrusive, the old
|
||||||
too intrusive, the old and new versions will not be matched during the PO
|
and new versions will not be matched during the first po4a run after
|
||||||
update, and the corresponding translation will be dumped anyway. But do not
|
gettextization (see below). Any unmatched translation will be dumped anyway.
|
||||||
hesitate to also edit the original document if required: the important thing is
|
That being said, you still want to edit the original document if it's too hard
|
||||||
to get a first PO file to start with.
|
to get the gettextization to proceed otherwise, even if it means that one
|
||||||
|
paragraph of the translation is dumped. The important thing is to get a first PO
|
||||||
|
file to start with.
|
||||||
|
|
||||||
=item
|
=item
|
||||||
|
|
||||||
|
@ -225,9 +220,11 @@ when synchronizing the PO file with the document.
|
||||||
=item
|
=item
|
||||||
|
|
||||||
You should probably inform the original author of any structural change in the
|
You should probably inform the original author of any structural change in the
|
||||||
translation that seems justified. Issues in the original document should reported
|
translation that seems justified. Issues in the original document should
|
||||||
to the author. Fixing them in your translation only fixes them for a part of the
|
reported to the author. Fixing them in your translation only fixes them for a
|
||||||
community. Plus, it is impossible to do so when using po4a ;)
|
part of the community. Plus, it is impossible to do so when using po4a ;) But
|
||||||
|
you probably want to wait until the end of the conversion to B<po4a> before
|
||||||
|
changing the original files.
|
||||||
|
|
||||||
=item
|
=item
|
||||||
|
|
||||||
|
@ -247,48 +244,74 @@ line and the content of the item.
|
||||||
Sometimes, the desynchronization message seems odd because the translation is
|
Sometimes, the desynchronization message seems odd because the translation is
|
||||||
attached to the wrong original paragraph. It is the sign of an undetected issue
|
attached to the wrong original paragraph. It is the sign of an undetected issue
|
||||||
earlier in the process. Search for the actual desynchronization point by
|
earlier in the process. Search for the actual desynchronization point by
|
||||||
inspecting F<gettextization.failed.po>, and fix the problem where it really is.
|
inspecting the file F<gettextization.failed.po> that was produced, and fix the
|
||||||
|
problem where it really is.
|
||||||
|
|
||||||
=item
|
=item
|
||||||
|
|
||||||
In some unfortunate settings, you will get the feeling that po4a ate some parts
|
Other issues may come from duplicated strings in either the original or
|
||||||
of the text, either the original or the translation. F<gettextization.failed.po>
|
translation. Duplicated strings are merged in PO files, with two references.
|
||||||
indicates that both files matched as expected up to the paragraph N. But then,
|
This constitutes a difficulty for the gettextization algorithm, that is a simple
|
||||||
an (unsuccessful) attempt is made to match the N+1 paragraph in the original
|
one to one pairing between the B<msgid>s of both the master and the localized
|
||||||
file not with the N+1 paragraph in the translation as it should, but with the
|
files. It is however believed that recent versions of po4a deal properly with
|
||||||
N+2 paragraph. Just as if the N+1 paragraph that you see in the document simply
|
duplicated strings, so you should report any remaining issue that you may encounter.
|
||||||
disappeared from the file during the process.
|
|
||||||
|
|
||||||
This unfortunate situation happens when the same paragraph is repeated over
|
|
||||||
the document. In that case, no new entry is created in the PO file, but a
|
|
||||||
new reference is added to the existing one instead.
|
|
||||||
|
|
||||||
So, the previous situation occurs when two similar but different paragraphs are
|
|
||||||
translated in the exact same way. This will apparently remove a paragraph of the
|
|
||||||
translation. To fix the problem, it is sufficient to slightly alter one of the
|
|
||||||
translations in the document. You can also prefer to kill the second paragraph
|
|
||||||
in the original document.
|
|
||||||
|
|
||||||
To the opposite, if the same paragraph appearing twice in the original document
|
|
||||||
is not translated in the exact same way at both locations, you will get the
|
|
||||||
feeling that one paragraph of the original document just vanished. Just copy the
|
|
||||||
best translation over the other one in the translated document to fix the
|
|
||||||
problem.
|
|
||||||
|
|
||||||
=item
|
|
||||||
|
|
||||||
As a final note, do not be too surprised if the first synchronization of your PO
|
|
||||||
file takes a long time. This is because most of the msgid of the PO file
|
|
||||||
resulting from the gettextization don't match exactly any element of the POT
|
|
||||||
file built from the recent master files. This forces gettext to search for the
|
|
||||||
closest one using a costly string proximity algorithm.
|
|
||||||
|
|
||||||
For example, the first B<po4a-updatepo> of the Perl documentation's French
|
|
||||||
translation (5.5 MB PO file) took about 48 hours (yes, two days) while the
|
|
||||||
subsequent ones only take a dozen of seconds.
|
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
=head2 Reviewing files produced by B<po4a-gettextize>
|
||||||
|
|
||||||
|
Any file produced by B<po4a-gettextize> should be manually reviewed, even when
|
||||||
|
the script terminates successfully. You should skim over the PO file, ensuring
|
||||||
|
that the B<msgid> and B<msgstr> actually match. It is not necessary to ensure
|
||||||
|
that the translation is perfectly correct yet, as all entries are marked as
|
||||||
|
fuzzy translations anyway. You only need to check for obvious matching issues
|
||||||
|
because badly matched translations will be dumped in subsequent steps while you
|
||||||
|
want to salvage them.
|
||||||
|
|
||||||
|
Fortunately, this step does not require to master the target languages as you
|
||||||
|
only want to recognize similar elements in each B<msgid> and its corresponding
|
||||||
|
B<msgstr>. As a speaker of French, English, and some German myself, I can do
|
||||||
|
this for all European languages at least, even if I cannot say one word of most
|
||||||
|
of these languages. I sometimes manage to detect matching issues in non-Latin
|
||||||
|
languages by looking at string length, phrase structures (does the amount of
|
||||||
|
interrogation marks match?) and other clues, but I prefer when someone else can
|
||||||
|
review those languages.
|
||||||
|
|
||||||
|
If you detect a mismatch, edit the original and translation files as if
|
||||||
|
B<po4a-gettextize> reported an error, and try again. Once you have a decent PO
|
||||||
|
file for your previous translation, backup it until you get po4a working
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
=head2 Running B<po4a> for the first time
|
||||||
|
|
||||||
|
The easiest way to setup po4a is to write a B<po4a.conf> configuration file, and
|
||||||
|
use the integrated po4a program (B<po4a-updatepo> and B<po4a-translate> are
|
||||||
|
deprecated). Please check the "CONFIGURATION FILE" Section in L<po4a(1)>
|
||||||
|
documentation for more details.
|
||||||
|
|
||||||
|
When B<po4a> runs for the first time, the current version of the master
|
||||||
|
documents will be used to update the PO files containing the old translations
|
||||||
|
that you salvaged through gettextization. This can take quite a long time,
|
||||||
|
because many of the B<msgid>s of from the gettextization do not exactly match
|
||||||
|
the elements of the POT file built from the recent master files. This forces
|
||||||
|
gettext to search for the closest one using a costly string proximity algorithm.
|
||||||
|
For example, the first run over the Perl documentation's French translation (5.5
|
||||||
|
MB PO file) took about 48 hours (yes, two days) while the subsequent ones only
|
||||||
|
take seconds.
|
||||||
|
|
||||||
|
=head2 Moving your translations to production
|
||||||
|
|
||||||
|
After this first run, the PO files are ready to be reviewed by translators. All
|
||||||
|
entries were marked as fuzzy in the PO file by B<po4a-gettextization>, forcing
|
||||||
|
their careful review before use. Translators should take each entry to verify
|
||||||
|
that the salvaged translation actually match the current original text, update
|
||||||
|
the translation on need, and remove the fuzzy markers.
|
||||||
|
|
||||||
|
Once enough fuzzy markers are removed, B<po4a> will start generating the
|
||||||
|
translation files on disk, and you're ready to move your translation workflow to
|
||||||
|
production. Some projects find it useful to rely on weblate to coordinate
|
||||||
|
between translators and maintainers, but that's beyond B<po4a>' scope.
|
||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
L<po4a(1)>,
|
L<po4a(1)>,
|
||||||
|
@ -300,12 +323,12 @@ L<po4a(7)>.
|
||||||
=head1 AUTHORS
|
=head1 AUTHORS
|
||||||
|
|
||||||
Denis Barbier <barbier@linuxfr.org>
|
Denis Barbier <barbier@linuxfr.org>
|
||||||
Nicolas Francois <nicolas.francois@centraliens.net>
|
Nicolas François <nicolas.francois@centraliens.net>
|
||||||
Martin Quinson (mquinson#debian.org)
|
Martin Quinson (mquinson#debian.org)
|
||||||
|
|
||||||
=head1 COPYRIGHT AND LICENSE
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
Copyright 2002-2020 by SPI, inc.
|
Copyright 2002-2022 by SPI, inc.
|
||||||
|
|
||||||
This program is free software; you may redistribute it and/or modify it
|
This program is free software; you may redistribute it and/or modify it
|
||||||
under the terms of GPL (see the COPYING file).
|
under the terms of GPL (see the COPYING file).
|
||||||
|
@ -324,8 +347,170 @@ use Locale::Po4a::Common;
|
||||||
|
|
||||||
use Pod::Usage qw(pod2usage);
|
use Pod::Usage qw(pod2usage);
|
||||||
|
|
||||||
|
our %debug = (
|
||||||
|
'encoding' => 0,
|
||||||
|
);
|
||||||
|
|
||||||
Locale::Po4a::Common::textdomain('po4a');
|
Locale::Po4a::Common::textdomain('po4a');
|
||||||
|
|
||||||
|
# This function produces one translated message catalog from two catalogs, an
|
||||||
|
# original and a translation. This process is described in L<po4a(7)|po4a.7>,
|
||||||
|
# section I<Gettextization: how does it work?>.
|
||||||
|
|
||||||
|
sub gettextize {
|
||||||
|
my ( $poorig, $potrans ) = ( shift, shift );
|
||||||
|
|
||||||
|
my $pores = Locale::Po4a::Po->new();
|
||||||
|
|
||||||
|
my $please_fail = 0;
|
||||||
|
my $toobad = dgettext( "po4a",
|
||||||
|
"\nThe gettextization failed (once again). Don't give up, "
|
||||||
|
. "gettextizing is a subtle art, but this is only needed once "
|
||||||
|
. "to convert a project to the gorgeous luxus offered by po4a "
|
||||||
|
. "to translators."
|
||||||
|
. "\nPlease refer to the po4a(7) documentation, the section "
|
||||||
|
. "\"HOWTO convert a pre-existing translation to po4a?\" "
|
||||||
|
. "contains several hints to help you in your task" );
|
||||||
|
|
||||||
|
# Don't fail right now when the entry count does not match. Instead, give
|
||||||
|
# it a try so that the user can see where we fail (which is probably where
|
||||||
|
# the problem is).
|
||||||
|
if ( $poorig->count_entries_doc() > $potrans->count_entries_doc() ) {
|
||||||
|
warn wrap_mod(
|
||||||
|
"po4a gettextize",
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"Original has more strings than the translation (%d>%d). "
|
||||||
|
. "Please fix it by editing the translated version to add "
|
||||||
|
. "some dummy entry."
|
||||||
|
),
|
||||||
|
$poorig->count_entries_doc(),
|
||||||
|
$potrans->count_entries_doc()
|
||||||
|
);
|
||||||
|
$please_fail = 1;
|
||||||
|
} elsif ( $poorig->count_entries_doc() < $potrans->count_entries_doc() ) {
|
||||||
|
warn wrap_mod(
|
||||||
|
"po4a gettextize",
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"Original has less strings than the translation (%d<%d). "
|
||||||
|
. "Please fix it by removing the extra entry from the "
|
||||||
|
. "translated file. You may need an addendum (cf po4a(7)) "
|
||||||
|
. "to reput the chunk in place after gettextization. A "
|
||||||
|
. "possible cause is that a text duplicated in the original "
|
||||||
|
. "is not translated the same way each time. Remove one of "
|
||||||
|
. "the translations, and you're fine."
|
||||||
|
),
|
||||||
|
$poorig->count_entries_doc(),
|
||||||
|
$potrans->count_entries_doc()
|
||||||
|
);
|
||||||
|
$please_fail = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $poorig->get_charset =~ /^utf-8$/i ) {
|
||||||
|
$potrans->to_utf8;
|
||||||
|
$pores->set_charset("UTF-8");
|
||||||
|
} else {
|
||||||
|
my $charset = $potrans->get_charset();
|
||||||
|
$charset = "UTF-8" if $charset eq "CHARSET";
|
||||||
|
$pores->set_charset($charset);
|
||||||
|
}
|
||||||
|
print "Po character sets:\n"
|
||||||
|
. " original="
|
||||||
|
. $poorig->get_charset . "\n"
|
||||||
|
. " translated="
|
||||||
|
. $potrans->get_charset . "\n"
|
||||||
|
. " result="
|
||||||
|
. $pores->get_charset . "\n"
|
||||||
|
if $debug{'encoding'};
|
||||||
|
|
||||||
|
for (
|
||||||
|
my ( $o, $t ) = ( 0, 0 ) ;
|
||||||
|
$o < $poorig->count_entries_doc() && $t < $potrans->count_entries_doc() ;
|
||||||
|
$o++, $t++
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#
|
||||||
|
# Extract some informations
|
||||||
|
|
||||||
|
my ( $orig, $trans ) = ( $poorig->msgid_doc($o), $potrans->msgid_doc($t) );
|
||||||
|
|
||||||
|
# print STDERR "Matches [[$orig]]<<$trans>>\n";
|
||||||
|
|
||||||
|
my ( $reforig, $reftrans ) = ( $poorig->{po}{$orig}{'reference'}, $potrans->{po}{$trans}{'reference'} );
|
||||||
|
my ( $typeorig, $typetrans ) = ( $poorig->type_doc($o), $potrans->type_doc($t) );
|
||||||
|
|
||||||
|
#
|
||||||
|
# Make sure the type of both string exist
|
||||||
|
#
|
||||||
|
die wrap_mod( "po4a gettextize", "Internal error: type of original string number %s isn't provided", $o )
|
||||||
|
if ( $typeorig eq '' );
|
||||||
|
|
||||||
|
die wrap_mod( "po4a gettextize", "Internal error: type of translated string number %s isn't provided", $o )
|
||||||
|
if ( $typetrans eq '' );
|
||||||
|
|
||||||
|
#
|
||||||
|
# Make sure both type are the same
|
||||||
|
#
|
||||||
|
if ( $typeorig ne $typetrans ) {
|
||||||
|
$pores->write("gettextization.failed.po");
|
||||||
|
eval {
|
||||||
|
# Recode $trans into current charset, if possible
|
||||||
|
require I18N::Langinfo;
|
||||||
|
I18N::Langinfo->import(qw(langinfo CODESET));
|
||||||
|
my $codeset = langinfo( CODESET() );
|
||||||
|
Encode::from_to( $trans, $potrans->get_charset, $codeset );
|
||||||
|
};
|
||||||
|
die wrap_msg(
|
||||||
|
dgettext( "po4a",
|
||||||
|
"po4a gettextization: Structure disparity between "
|
||||||
|
. "original and translated files:\n"
|
||||||
|
. "msgid (at %s) is of type '%s' while\n"
|
||||||
|
. "msgstr (at %s) is of type '%s'.\n"
|
||||||
|
. "Original text: %s\n"
|
||||||
|
. "Translated text: %s\n"
|
||||||
|
. "(result so far dumped to gettextization.failed.po)" )
|
||||||
|
. "%s",
|
||||||
|
$reforig,
|
||||||
|
$typeorig,
|
||||||
|
$reftrans,
|
||||||
|
$typetrans,
|
||||||
|
$orig, $trans, $toobad
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Push the entry
|
||||||
|
#
|
||||||
|
my $flags;
|
||||||
|
if ( defined $poorig->{po}{$orig}{'flags'} ) {
|
||||||
|
$flags = $poorig->{po}{$orig}{'flags'} . " fuzzy";
|
||||||
|
} else {
|
||||||
|
$flags = "fuzzy";
|
||||||
|
}
|
||||||
|
$pores->push_raw(
|
||||||
|
'msgid' => $orig,
|
||||||
|
'msgstr' => $trans,
|
||||||
|
'flags' => $flags,
|
||||||
|
'type' => $typeorig,
|
||||||
|
'reference' => $reforig,
|
||||||
|
'conflict' => 1,
|
||||||
|
'transref' => $potrans->{po}{$trans}{'reference'}
|
||||||
|
)
|
||||||
|
unless ( defined( $pores->{po}{$orig} )
|
||||||
|
and ( $pores->{po}{$orig}{'msgstr'} eq $trans ) )
|
||||||
|
|
||||||
|
# FIXME: maybe we should be smarter about what reference should be
|
||||||
|
# sent to push_raw.
|
||||||
|
}
|
||||||
|
|
||||||
|
# make sure we return a useful error message when entry count differ
|
||||||
|
die "$toobad\n" if $please_fail;
|
||||||
|
|
||||||
|
return $pores;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sub show_version {
|
sub show_version {
|
||||||
Locale::Po4a::Common::show_version("po4a-gettextize");
|
Locale::Po4a::Common::show_version("po4a-gettextize");
|
||||||
exit 0;
|
exit 0;
|
||||||
|
@ -341,12 +526,13 @@ my %opts = (
|
||||||
);
|
);
|
||||||
|
|
||||||
my ($pofile) = ('-');
|
my ($pofile) = ('-');
|
||||||
my ( @masterfile, @locfile, $help_fmt, $help, $type, @options );
|
my ( @masterfile, @locfile, $help_fmt, $help, $keep_temps, $type, @options );
|
||||||
my ( $mastchar, $locchar );
|
my ( $mastchar, $locchar );
|
||||||
Getopt::Long::config( 'bundling', 'no_getopt_compat', 'no_auto_abbrev' );
|
Getopt::Long::config( 'bundling', 'no_getopt_compat', 'no_auto_abbrev' );
|
||||||
GetOptions(
|
GetOptions(
|
||||||
'help|h' => \$help,
|
'help|h' => \$help,
|
||||||
'help-format' => \$help_fmt,
|
'help-format' => \$help_fmt,
|
||||||
|
'keep-temps|k' => \$keep_temps,
|
||||||
|
|
||||||
'master|m=s' => \@masterfile,
|
'master|m=s' => \@masterfile,
|
||||||
'localized|l=s' => \@locfile,
|
'localized|l=s' => \@locfile,
|
||||||
|
@ -382,11 +568,25 @@ foreach (@options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scalar @locfile == 0) {
|
||||||
|
die wrap_msg(gettext("You must provide the same amount of master files and localized files to synchronize them, ".
|
||||||
|
"as po4a-gettextize is intended to synchronize master files and previously existing translations. ".
|
||||||
|
"If just want to extract POT files of your master files, please use po4a-updatepo. ".
|
||||||
|
"Please note that the most convenient way of using po4a is to write a po4a.conf file and use the integrated po4a(1) program."))
|
||||||
|
}
|
||||||
|
|
||||||
# Check file existence
|
# Check file existence
|
||||||
foreach my $file ( @masterfile, @locfile ) {
|
foreach my $file ( @masterfile, @locfile ) {
|
||||||
$file eq '-' || -e $file || die wrap_msg( gettext("File %s does not exist."), $file );
|
$file eq '-' || -e $file || die wrap_msg( gettext("File %s does not exist."), $file );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print wrap_msg(
|
||||||
|
gettext(
|
||||||
|
"po4a-gettextize is only useful to convert previously existing translations to a PO based workflow. "
|
||||||
|
. "Once you successfully converted your project to po4a, you should use the po4a(1) program to maintain it and update your translations."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
# Declare the TransTractor parsers
|
# Declare the TransTractor parsers
|
||||||
my ( $mastertt, $transtt ) = ( Locale::Po4a::Chooser::new( $type, %opts ), Locale::Po4a::Chooser::new( $type, %opts ) );
|
my ( $mastertt, $transtt ) = ( Locale::Po4a::Chooser::new( $type, %opts ), Locale::Po4a::Chooser::new( $type, %opts ) );
|
||||||
|
|
||||||
|
@ -408,27 +608,30 @@ $mastertt->parse;
|
||||||
# translation files to extract two PO files. A third PO file is built from them
|
# translation files to extract two PO files. A third PO file is built from them
|
||||||
# taking strings from the second as translation of strings from the first.
|
# taking strings from the second as translation of strings from the first.
|
||||||
|
|
||||||
unless ( scalar @locfile >= 1 ) {
|
# Let's merge the two transtractor files
|
||||||
|
|
||||||
# Ok, outputing the pot extracted from original is enough
|
foreach my $file (@locfile) {
|
||||||
$mastertt->writepo($pofile);
|
$transtt->read( $file, $file );
|
||||||
} else {
|
|
||||||
|
|
||||||
# We have to merge two transtractor files
|
|
||||||
|
|
||||||
foreach my $file (@locfile) {
|
|
||||||
$transtt->read( $file, $file );
|
|
||||||
}
|
|
||||||
|
|
||||||
# We force the conversion to utf if the master document wasn't in ascii
|
|
||||||
$transtt->{TT}{utf_mode} = !$mastertt->{TT}{ascii_input};
|
|
||||||
$transtt->detected_charset($locchar);
|
|
||||||
$transtt->{TT}{po_in}->set_charset($locchar);
|
|
||||||
$transtt->parse;
|
|
||||||
|
|
||||||
my $mergedpo = Locale::Po4a::Po->gettextize( $mastertt->getpoout(), $transtt->getpoout() );
|
|
||||||
|
|
||||||
$mergedpo->write($pofile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# We force the conversion to utf if the master document wasn't in ascii
|
||||||
|
$transtt->{TT}{utf_mode} = !$mastertt->{TT}{ascii_input};
|
||||||
|
$transtt->detected_charset($locchar);
|
||||||
|
$transtt->{TT}{po_in}->set_charset($locchar);
|
||||||
|
$transtt->parse;
|
||||||
|
|
||||||
|
if ($keep_temps) {
|
||||||
|
$mastertt->getpoout()->write("po4atemp.master.po");
|
||||||
|
$transtt->getpoout()->write("po4atemp.localized.po");
|
||||||
|
print wrap_msg(
|
||||||
|
dgettext(
|
||||||
|
"po4a",
|
||||||
|
"Temporary master and localized POT files dumped to po4atemp.master.po and po4atemp.localized.po"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
my $mergedpo = gettextize( $mastertt->getpoout(), $transtt->getpoout() );
|
||||||
|
|
||||||
|
$mergedpo->write($pofile);
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue