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_author => ['Martin Quinson (mquinson#debian.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>']
|
||||
);
|
||||
|
||||
|
|
79
MANIFEST
79
MANIFEST
|
@ -64,6 +64,7 @@ po/bin/hu.po
|
|||
po/bin/id.po
|
||||
po/bin/it.po
|
||||
po/bin/ja.po
|
||||
po/bin/ka.po
|
||||
po/bin/kn.po
|
||||
po/bin/ko.po
|
||||
po/bin/nb.po
|
||||
|
@ -101,6 +102,7 @@ po/pod/ru.po
|
|||
po/pod/sr_Cyrl.po
|
||||
po/pod/uk.po
|
||||
po/pod/zh_CHS.po
|
||||
po/pod/zh_Hant.po
|
||||
msguntypot
|
||||
po4a
|
||||
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/po4a.conf
|
||||
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/multiple.it.po
|
||||
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.pot
|
||||
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.norm
|
||||
t/fmt/asciidoc/Lists.norm.stderr
|
||||
|
@ -675,6 +689,11 @@ t/fmt/asciidoc/Lists.po
|
|||
t/fmt/asciidoc/Lists.pot
|
||||
t/fmt/asciidoc/Lists.trans
|
||||
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.norm
|
||||
t/fmt/asciidoc/NoImageTarget.po
|
||||
|
@ -724,6 +743,11 @@ t/fmt/asciidoc/YamlFrontMatter.norm
|
|||
t/fmt/asciidoc/YamlFrontMatter.po
|
||||
t/fmt/asciidoc/YamlFrontMatter.pot
|
||||
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.norm
|
||||
t/fmt/asciidoc/YamlFrontMatter_Option.po
|
||||
|
@ -795,6 +819,20 @@ t/fmt/man/macros.norm
|
|||
t/fmt/man/macros.po
|
||||
t/fmt/man/macros.pot
|
||||
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.norm
|
||||
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/YamlFrontMatter.md
|
||||
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.norm
|
||||
t/fmt/txt-markdown/YamlFrontMatter_Options.po
|
||||
t/fmt/txt-markdown/YamlFrontMatter_Options.pot
|
||||
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.po
|
||||
t/fmt/wml/basic.pot
|
||||
|
@ -1014,6 +1064,11 @@ t/fmt/xhtml/includessi.norm
|
|||
t/fmt/xhtml/includessi.po
|
||||
t/fmt/xhtml/includessi.pot
|
||||
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.norm
|
||||
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.pot
|
||||
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.norm
|
||||
t/fmt/xml/options.po
|
||||
t/fmt/xml/options.pot
|
||||
t/fmt/xml/options.trans
|
||||
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.po
|
||||
t/fmt/yaml/basic.pot
|
||||
|
@ -1081,6 +1146,13 @@ t/fmt/yaml/utf8.po
|
|||
t/fmt/yaml/utf8.pot
|
||||
t/fmt/yaml/utf8.trans
|
||||
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/cfg-args.t
|
||||
|
@ -1107,6 +1179,7 @@ t/fmt-xhtml.t
|
|||
t/fmt-xml-dia.t
|
||||
t/fmt-xml.t
|
||||
t/fmt-yaml.t
|
||||
t/gettextize.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
|
||||
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%).
|
||||
3 languages >= 50%: ja (69%), pl (69%), ru (69%).
|
||||
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('docs');
|
||||
$self->depends_on('distmeta'); # regenerate META.yml
|
||||
$self->depends_on('man');
|
||||
$self->depends_on('postats');
|
||||
$self->depends_on('man') unless ($^O eq 'MSWin32');
|
||||
$self->depends_on('postats') unless ($^O eq 'MSWin32');
|
||||
}
|
||||
|
||||
sub make_files_writable {
|
||||
|
@ -234,27 +234,29 @@ sub ACTION_man {
|
|||
}
|
||||
$parser->parse_from_file ($file, $out);
|
||||
|
||||
system("gzip -9 -f $out") and die;
|
||||
system("gzip -9 -n -f $out") and die;
|
||||
unlink "$file" || die;
|
||||
}
|
||||
|
||||
# Install the manpages written in XML DocBook
|
||||
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$,) {
|
||||
my ($outdir, $section, $outfile) = ($1, $2, $3);
|
||||
if (-e "/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl") { # Location on Debian at least
|
||||
print "Convert $outdir/$outfile.$section (local docbook.xsl file). ";
|
||||
system("xsltproc -o $outdir/$outfile.$section --nonet /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl $file") and die;
|
||||
} else { # Not found locally, use the XSL file online
|
||||
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;
|
||||
if ($^O ne 'MSWin32') {
|
||||
# Install the manpages written in XML DocBook
|
||||
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$,) {
|
||||
my ($outdir, $section, $outfile) = ($1, $2, $3);
|
||||
if (-e "/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl") { # Location on Debian at least
|
||||
print "Convert $outdir/$outfile.$section (local docbook.xsl file). ";
|
||||
system("xsltproc -o $outdir/$outfile.$section --nonet /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl $file") and die;
|
||||
} else { # Not found locally, use the XSL file online
|
||||
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 -n -f $outdir/$outfile.$section") and die;
|
||||
}
|
||||
unlink "$file" || die;
|
||||
}
|
||||
unlink "$file" || die;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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)
|
||||
|
||||
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
|
||||
under the terms of GPL (see COPYING file).
|
||||
|
||||
Copyright © 2002-2021 by SPI, inc.
|
||||
Copyright © 2002-2022 by SPI, inc.
|
||||
|
||||
Authors:
|
||||
- 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
|
||||
of shadow and dpkg.
|
||||
- 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
|
||||
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
|
||||
given only one argument, that's the designator (which we have to
|
||||
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
|
||||
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
|
||||
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
|
||||
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?
|
||||
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
|
||||
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
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
my %yfm_keys = ();
|
||||
|
@ -130,6 +131,19 @@ Do not translate array values in the YAML Front Matter section.
|
|||
|
||||
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
|
||||
|
||||
=head1 INLINE CUSTOMIZATION
|
||||
|
@ -142,12 +156,12 @@ The following commands are recognized:
|
|||
|
||||
=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
|
||||
if the target must be translated.
|
||||
|
||||
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.
|
||||
|
||||
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<]>
|
||||
|
||||
This permits to describe in detail which attributes of a style must
|
||||
This describes in detail which attributes of a style must
|
||||
be translated.
|
||||
|
||||
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.
|
||||
The first attribute is the style name, it will not be translated.
|
||||
|
||||
|
@ -205,6 +219,7 @@ sub initialize {
|
|||
$self->{options}{'compat'} = 'asciidoc';
|
||||
$self->{options}{'yfm_keys'} = '';
|
||||
$self->{options}{'yfm_skip_array'} = 0;
|
||||
$self->{options}{'yfm_paths'} = '';
|
||||
$self->{options}{'nolinting'} = 0;
|
||||
|
||||
foreach my $opt ( keys %options ) {
|
||||
|
@ -228,8 +243,11 @@ sub initialize {
|
|||
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||
$yfm_keys{$_} = 1
|
||||
} ( 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'};
|
||||
|
||||
$self->{translate} = {
|
||||
|
@ -349,6 +367,7 @@ BEGIN {
|
|||
my $UnicodeGCString_available = 0;
|
||||
$UnicodeGCString_available = 1 if ( eval { require Unicode::GCString } );
|
||||
eval {
|
||||
|
||||
sub chars($$$) {
|
||||
my $text = 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 {
|
||||
my $self = shift;
|
||||
my ( $line, $ref ) = $self->shiftline();
|
||||
|
@ -389,7 +424,8 @@ sub parse {
|
|||
my $yamlarray = YAML::Tiny->read_string($yfm)
|
||||
|| 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 '---'
|
||||
}
|
||||
|
@ -439,7 +475,7 @@ sub parse {
|
|||
and ( $self->{type} eq "Table" )
|
||||
and ( $line !~ m/^\|===/ )
|
||||
and ( $self->{options}{"tablecells"} )
|
||||
and (not defined $self->{disabletablecells}))
|
||||
and ( not defined $self->{disabletablecells} ) )
|
||||
{
|
||||
# inside a table, and we should split per cell
|
||||
my $new_line = "";
|
||||
|
@ -463,8 +499,10 @@ sub parse {
|
|||
my @parts = map { ( $_, shift @texts ) } @seps;
|
||||
foreach my $part (@parts) {
|
||||
if ( not defined $part ) {
|
||||
# allows concatenation and will be stripped anyway
|
||||
$part = " "; }
|
||||
|
||||
# allows concatenation and will be stripped anyway
|
||||
$part = " ";
|
||||
}
|
||||
if ( $part =~ /\|$/ ) {
|
||||
|
||||
# this is a cell separator. End the previous cell
|
||||
|
@ -695,9 +733,9 @@ sub parse {
|
|||
}
|
||||
print STDERR "Starting verse\n" if $debug{parse};
|
||||
}
|
||||
if ((( $line =~ m/^\[format=(['"]?)(csv|tsv|dsv)\1,/ ) ||
|
||||
( $line =~ m/^\[separator=[^\|]/ )) &&
|
||||
$self->{options}{'tablecells'}) {
|
||||
if ( ( ( $line =~ m/^\[format=(['"]?)(csv|tsv|dsv)\1,/ ) || ( $line =~ m/^\[separator=[^\|]/ ) )
|
||||
&& $self->{options}{'tablecells'} )
|
||||
{
|
||||
warn wrap_mod(
|
||||
"$ref",
|
||||
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."
|
||||
)
|
||||
);
|
||||
$self->{disabletablecells} = 1;
|
||||
$self->{disabletablecells} = 1;
|
||||
}
|
||||
undef $self->{bullet};
|
||||
undef $self->{indent};
|
||||
|
@ -787,7 +825,7 @@ sub parse {
|
|||
}
|
||||
@comments = ();
|
||||
} 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 $macrotype = $2;
|
||||
|
@ -852,7 +890,7 @@ sub parse {
|
|||
$self->{indent} = $indent;
|
||||
$self->{bullet} = $bullet;
|
||||
} elsif ( not defined $self->{verbatim}
|
||||
and ( $line =~ m/^((?:<?[0-9]+)?> +)(.*)$/ ) )
|
||||
and ( $line =~ m/^((?:<?(?:[0-9]|\.)+)?> +)(.*)$/ ) )
|
||||
{
|
||||
my $bullet = $1;
|
||||
my $text = $2;
|
||||
|
@ -966,8 +1004,9 @@ sub parse {
|
|||
} else {
|
||||
|
||||
# End the Table
|
||||
if ( $self->{options}{'tablecells'} and
|
||||
not defined $self->{disabletablecells} ) {
|
||||
if ( $self->{options}{'tablecells'}
|
||||
and not defined $self->{disabletablecells} )
|
||||
{
|
||||
do_stripped_unwrapped_paragraph( $self, $paragraph, $wrapped_mode );
|
||||
$self->pushline("\n");
|
||||
} else {
|
||||
|
@ -975,7 +1014,7 @@ sub parse {
|
|||
}
|
||||
undef $self->{verbatim};
|
||||
undef $self->{type};
|
||||
undef $self->{disabletablecells};
|
||||
undef $self->{disabletablecells};
|
||||
$paragraph = "";
|
||||
}
|
||||
$self->pushline( $line . "\n" );
|
||||
|
@ -996,21 +1035,21 @@ sub parse {
|
|||
$wrapped_mode = 0;
|
||||
}
|
||||
|
||||
if ( ( $paragraph ne "" && $self->{bullet} && length( $self->{indent} || "" ) == 0 )
|
||||
&& ( !$self->{options}{'nolinting'} ) )
|
||||
if ( ( $paragraph ne "" && $self->{bullet} && length( $self->{indent} || "" ) == 0 ) )
|
||||
{
|
||||
|
||||
# Second line of an item block is not indented. It is unindented
|
||||
# (and allowed) additional text or a new list item.
|
||||
warn wrap_mod(
|
||||
"$ref",
|
||||
dgettext(
|
||||
"po4a",
|
||||
"It seems that you are adding unindented content to an item. "
|
||||
. "The standard allows this, but you may still want to change your document "
|
||||
. "to use indented text to provide better visual clues to writers."
|
||||
)
|
||||
);
|
||||
if ( !$self->{options}{'nolinting'} ) {
|
||||
# Second line of an item block is not indented. It is unindented
|
||||
# (and allowed) additional text or a new list item.
|
||||
warn wrap_mod(
|
||||
"$ref",
|
||||
dgettext(
|
||||
"po4a",
|
||||
"It seems that you are adding unindented content to an item. "
|
||||
. "The standard allows this, but you may still want to change your document "
|
||||
. "to use indented text to provide better visual clues to writers."
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
undef $self->{bullet};
|
||||
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")."'";
|
||||
|
||||
if ( not $wrap and not defined $self->{verbatim} ) {
|
||||
if ( not defined $self->{verbatim} ) {
|
||||
|
||||
# Detect bullets
|
||||
# | * blah blah
|
||||
|
@ -1121,8 +1160,10 @@ sub do_paragraph {
|
|||
"comment" => join( "\n", @comments ),
|
||||
"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) {
|
||||
$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
|
||||
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(
|
||||
"%s version %s.\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"
|
||||
. "conditions. There is NO warranty; not even for\n"
|
||||
. "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:
|
||||
|
||||
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.
|
||||
|
||||
The adaptation for po4a was done by:
|
||||
|
|
|
@ -119,7 +119,7 @@ Increase verbosity.
|
|||
|
||||
=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:
|
||||
|
||||
=over
|
||||
|
@ -148,8 +148,8 @@ should be preferred.
|
|||
|
||||
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.
|
||||
This permits to use po4a on generated man pages.
|
||||
This option does not take any argument.
|
||||
This option is mandatory to use po4a on generated man pages.
|
||||
Note that translating generated pages instead of sources ones is often more fragile, and thus a bad idea.
|
||||
|
||||
=item B<mdoc>
|
||||
|
||||
|
@ -173,8 +173,8 @@ This mdoc issue can also be solved with an addendum like this one:
|
|||
|
||||
=back
|
||||
|
||||
The following options permit to specify the behavior of a new macro
|
||||
(defined with a .de request), or of a macro not supported by po4a.
|
||||
The following options specify the behavior of a user-defined macro
|
||||
(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.
|
||||
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>
|
||||
(respectively I<begin>), you can specify an existing I<end> (like fi) or
|
||||
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>
|
||||
|
||||
|
@ -380,7 +380,7 @@ L<po4a(7)|po4a.7>
|
|||
=head1 AUTHORS
|
||||
|
||||
Denis Barbier <barbier@linuxfr.org>
|
||||
Nicolas Francois <nicolas.francois@centraliens.net>
|
||||
Nicolas François <nicolas.francois@centraliens.net>
|
||||
Martin Quinson (mquinson#debian.org)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
@ -1036,15 +1036,14 @@ sub pre_trans {
|
|||
|
||||
$str =~ s/>/E<gt>/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 ) {
|
||||
my ( $t1, $t2, $t3 ) = ( $1, $2, $3 );
|
||||
$str = "$1E<$2>";
|
||||
if ($mdoc_mode) {
|
||||
|
||||
# When a punctuation sign must be joined to an argument, mdoc
|
||||
# permits to use such a construct:
|
||||
# When a punctuation sign must be joined to an argument, mdoc allows such a construct:
|
||||
# .Ar file1 , file2 , file3 ) .
|
||||
# Here, we move the punctuation out of the E<...> tag.
|
||||
# This is reverted in post_trans.
|
||||
|
@ -1202,7 +1201,12 @@ sub post_trans {
|
|||
} elsif ( $first eq '>' ) {
|
||||
$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 );
|
||||
}
|
||||
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).
|
||||
$macro{'ad'} = \&untranslated;
|
||||
|
||||
# .de macro Define or redefine macro until .. is encountered.
|
||||
$macro{'de'} = sub {
|
||||
my %ds_variables;
|
||||
|
||||
# .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;
|
||||
if ( $groff_code ne "fail" ) {
|
||||
my $paragraph = "@_";
|
||||
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 = $ds_variables{$end} if ( $_[0] eq "dei" || $_[0] eq "dei1" );
|
||||
}
|
||||
my ( $line, $ref ) = $self->SUPER::shiftline();
|
||||
chomp $line;
|
||||
|
@ -2223,26 +2291,17 @@ $macro{'de'} = sub {
|
|||
"po4a::man",
|
||||
dgettext(
|
||||
"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 name Set the current font family to name.
|
||||
$macro{'fam'} = \&untranslated;
|
||||
|
@ -2328,13 +2387,20 @@ $macro{'ie'} = $macro{'if'} = sub {
|
|||
"po4a::man",
|
||||
dgettext(
|
||||
"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).
|
||||
$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.
|
||||
$macro{'lf'} = \&untranslated;
|
||||
|
||||
|
@ -2417,9 +2486,9 @@ $macro{'ti'} = \&untranslated;
|
|||
###
|
||||
$macro{'TS'} = sub {
|
||||
my $self = shift;
|
||||
my ( $in_headers, $tab, $buffer ) = ( 1, "\t", "" );
|
||||
my ( $in_textblock, $preline, $postline ) = ( 0, "", "" );
|
||||
my ( $line, $ref ) = $self->shiftline();
|
||||
my ( $in_headers, $tab, $buffer ) = ( 1, "\t", "" );
|
||||
my ( $in_textblock, $preline, $postline ) = ( 0, "", "" );
|
||||
my ( $line, $ref ) = $self->shiftline();
|
||||
my @options;
|
||||
|
||||
# Push table start
|
||||
|
@ -2801,3 +2870,7 @@ sub define_mdoc_macros {
|
|||
$macro{'br'} = \&noarg;
|
||||
|
||||
} # 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
|
||||
# (duplicate strings counted multiple times)
|
||||
$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} =
|
||||
" SOME DESCRIPTIVE TITLE\n"
|
||||
. " Copyright (C) YEAR "
|
||||
|
@ -646,7 +649,7 @@ sub write_if_needed {
|
|||
my $basename = basename($filename);
|
||||
( undef, $tmp_filename ) = File::Temp::tempfile(
|
||||
$basename . "XXXX",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
OPEN => 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($)
|
||||
|
||||
This function extracts a catalog from an existing one. Only the entries having
|
||||
|
@ -1401,14 +1241,15 @@ sub push_raw {
|
|||
|
||||
if ($keep_conflict) {
|
||||
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 {
|
||||
$msgstr =
|
||||
"#-#-#-#-# "
|
||||
. $self->{po}{$msgid}{'transref'}
|
||||
. " #-#-#-#-#\\n"
|
||||
. " (type " . $self->{po}{$msgid}{'type'}
|
||||
. ") #-#-#-#-#\\n"
|
||||
. $self->{po}{$msgid}{'msgstr'} . "\\n"
|
||||
. "#-#-#-#-# $transref #-#-#-#-#\\n"
|
||||
. "#-#-#-#-# $transref (type: $type) #-#-#-#-#\\n"
|
||||
. $msgstr;
|
||||
}
|
||||
|
||||
|
@ -1451,11 +1292,11 @@ sub push_raw {
|
|||
$self->{po}{$msgid}{'comment'} = $comment;
|
||||
$self->{po}{$msgid}{'automatic'} = $automatic;
|
||||
$self->{po}{$msgid}{'previous'} = $previous;
|
||||
if ( defined( $self->{po}{$msgid}{'pos_doc'} ) ) {
|
||||
$self->{po}{$msgid}{'pos_doc'} .= " " . $self->{count_doc}++;
|
||||
} else {
|
||||
$self->{po}{$msgid}{'pos_doc'} = $self->{count_doc}++;
|
||||
}
|
||||
|
||||
$self->{po}{$msgid}{pos_doc} = () unless (defined( $self->{po}{$msgid}{pos_doc}));
|
||||
CORE::push( @{ $self->{po}{$msgid}{pos_doc} }, $self->{count_doc}++);
|
||||
CORE::push( @{ $self->{gettextize_types} }, $type);
|
||||
|
||||
unless ( defined( $self->{po}{$msgid}{'pos'} ) ) {
|
||||
$self->{po}{$msgid}{'pos'} = $self->{count}++;
|
||||
}
|
||||
|
@ -1515,37 +1356,6 @@ sub count_entries_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($)
|
||||
|
||||
Returns the msgid of the given number.
|
||||
|
@ -1573,13 +1383,29 @@ sub msgid_doc($$) {
|
|||
my $num = shift;
|
||||
|
||||
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 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()
|
||||
|
||||
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)
|
||||
sub quote_text {
|
||||
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);
|
||||
|
||||
|
|
|
@ -399,7 +399,7 @@ sub parse_file {
|
|||
my ( $tmpfh, $tmpfile ) = File::Temp::tempfile(
|
||||
"po4a-XXXX",
|
||||
SUFFIX => ".sgml",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
UNLINK => 0
|
||||
);
|
||||
print $tmpfh $origfile;
|
||||
|
@ -434,7 +434,7 @@ sub parse_file {
|
|||
# Get the prolog
|
||||
{
|
||||
$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
|
||||
|
||||
unless ( $prolog =~ s/^(.*<!DOCTYPE).*$/$1/is ) {
|
||||
|
@ -773,7 +773,7 @@ sub parse_file {
|
|||
while ( $origfile =~ /^(.*?)&$key(;.*$|[^-_:.A-Za-z0-9].*$|$)/s ) {
|
||||
|
||||
# Since we will include a new file, we
|
||||
# must do a new round of substitutions.
|
||||
# must do a new round of substitutions.
|
||||
$dosubstitution = 1;
|
||||
my ( $begin, $end ) = ( $1, $2 );
|
||||
$end = "" unless ( defined $end );
|
||||
|
@ -789,7 +789,7 @@ sub parse_file {
|
|||
# add the refs
|
||||
my $len = $entincl{$key}{'length'}; # number added by the inclusion
|
||||
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"
|
||||
if $debug{'refs'};
|
||||
|
||||
|
@ -852,7 +852,7 @@ sub parse_file {
|
|||
my ( $tmpfh, $tmpfile ) = File::Temp::tempfile(
|
||||
"po4a-XXXX",
|
||||
SUFFIX => ".sgml",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
UNLINK => 0
|
||||
);
|
||||
print $tmpfh $origfile;
|
||||
|
|
|
@ -166,8 +166,7 @@ this environment does not take any parameters.
|
|||
|
||||
=back
|
||||
|
||||
Using these options permits to override the behaviour of the commands defined
|
||||
in the default lists.
|
||||
Use these options to override the default behavior of the defined commands.
|
||||
|
||||
=head1 INLINE CUSTOMIZATION
|
||||
|
||||
|
@ -184,7 +183,7 @@ treated as the arguments of the I<command2> command.
|
|||
|
||||
=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.
|
||||
This information will be used to check the number of arguments and their
|
||||
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.
|
||||
The translator will have to translate the command concatenated to all its
|
||||
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).
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
\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
|
||||
others commands.
|
||||
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.
|
||||
|
||||
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.
|
||||
It may also need some escapes.
|
||||
|
||||
|
@ -1121,7 +1120,7 @@ sub parse_definition_line {
|
|||
}
|
||||
} elsif ( $line =~ /^separator\s+(\w+(?:\[#[0-9]+\])?)\s+\"(.*)\"\s*$/ ) {
|
||||
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;
|
||||
} elsif ( $line =~ /^verbatim\s+environment\s+(\w+)\s+$/ ) {
|
||||
register_verbatim_environment($1);
|
||||
|
@ -1721,7 +1720,7 @@ attached to the following string.
|
|||
=item Some commands should be added to the environment stack
|
||||
|
||||
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.
|
||||
|
||||
=item Others
|
||||
|
@ -1754,3 +1753,7 @@ under the terms of GPL (see the COPYING file).
|
|||
=cut
|
||||
|
||||
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::Common;
|
||||
use YAML::Tiny;
|
||||
use Syntax::Keyword::Try;
|
||||
|
||||
=head1 OPTIONS ACCEPTED BY THIS MODULE
|
||||
|
||||
|
@ -122,7 +123,7 @@ my $breaks;
|
|||
=item B<debianchangelog>
|
||||
|
||||
Handle the header and footer of
|
||||
released versions, which only contain non translatable informations.
|
||||
released versions, which only contain non translatable information.
|
||||
|
||||
=cut
|
||||
|
||||
|
@ -148,14 +149,41 @@ my $markdown = 0;
|
|||
=item B<yfm_keys> (markdown-only)
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
Do not translate array values in the YAML Front Matter section.
|
||||
|
@ -200,6 +228,8 @@ sub initialize {
|
|||
$self->{options}{'fortunes'} = 1;
|
||||
$self->{options}{'markdown'} = 1;
|
||||
$self->{options}{'yfm_keys'} = '';
|
||||
$self->{options}{'yfm_lenient'} = 0;
|
||||
$self->{options}{'yfm_paths'} = '';
|
||||
$self->{options}{'yfm_skip_array'} = 0;
|
||||
$self->{options}{'nobullets'} = 0;
|
||||
$self->{options}{'keyvalue'} = 1;
|
||||
|
@ -229,11 +259,16 @@ sub initialize {
|
|||
$_ =~ s/^\s+|\s+$//g; # Trim the keys before using them
|
||||
$yfm_keys{$_} = 1
|
||||
} ( 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_lenient = $self->{options}{'yfm_lenient'};
|
||||
} 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." ),
|
||||
$opt )
|
||||
if exists $options{$opt};
|
||||
|
@ -301,12 +336,12 @@ sub parse_fallback {
|
|||
if (
|
||||
$markdown
|
||||
and (
|
||||
$line =~ /\S $/ # explicit newline
|
||||
$line =~ /\S $/ # explicit newline
|
||||
or $line =~ /"""$/
|
||||
)
|
||||
)
|
||||
{ # """ textblock inside macro begin
|
||||
# Markdown markup needing separation _after_ this line
|
||||
{ # """ textblock inside macro begin
|
||||
# Markdown markup needing separation _after_ this line
|
||||
$end_of_paragraph = 1;
|
||||
} else {
|
||||
undef $self->{bullet};
|
||||
|
@ -576,18 +611,59 @@ sub parse_markdown_bibliographic_information {
|
|||
sub parse_markdown_yaml_front_matter {
|
||||
my ( $self, $line, $blockref ) = @_;
|
||||
my $yfm;
|
||||
my @saved_ctn;
|
||||
my ( $nextline, $nextref ) = $self->shiftline();
|
||||
push @saved_ctn, ( $nextline, $nextref );
|
||||
while ( defined($nextline) ) {
|
||||
last if ( $nextline =~ /^(---|\.\.\.)$/ );
|
||||
$yfm .= $nextline;
|
||||
( $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 );
|
||||
return;
|
||||
my $yamlarray; # the parsed YFM content
|
||||
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 {
|
||||
|
@ -602,8 +678,11 @@ sub parse_markdown {
|
|||
parse_markdown_bibliographic_information( $self, $line, $ref );
|
||||
return ( $paragraph, $wrapped_mode, $expect_header, $end_of_paragraph );
|
||||
} elsif ( $line =~ /^---$/ ) {
|
||||
parse_markdown_yaml_front_matter( $self, $line, $ref );
|
||||
return ( $paragraph, $wrapped_mode, $expect_header, $end_of_paragraph );
|
||||
if ( parse_markdown_yaml_front_matter( $self, $line, $ref ) ) { # successfully parsed
|
||||
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,})$/ )
|
||||
|
@ -682,6 +761,68 @@ sub parse_markdown {
|
|||
$self->pushline($nextline);
|
||||
$paragraph = "";
|
||||
$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 (
|
||||
$line =~ /^\s*\[\[\!\S+\s*$/ # macro begin
|
||||
or $line =~ /^\s*"""\s*\]\]\s*$/
|
||||
|
@ -698,8 +839,8 @@ sub parse_markdown {
|
|||
$paragraph = "$line\n";
|
||||
$wrapped_mode = 0;
|
||||
$end_of_paragraph = 1;
|
||||
} elsif ( $line =~ /^"""/ ) { # """ textblock inside macro end
|
||||
# Markdown markup needing separation _before_ this line
|
||||
} elsif ( $line =~ /^"""/ ) { # """ textblock inside macro end
|
||||
# Markdown markup needing separation _before_ this line
|
||||
do_paragraph( $self, $paragraph, $wrapped_mode );
|
||||
$paragraph = "$line\n";
|
||||
$wrapped_mode = $defaultwrap;
|
||||
|
@ -787,15 +928,10 @@ sub do_paragraph {
|
|||
$wrap = 0 unless $defaultwrap;
|
||||
|
||||
# DEBUG
|
||||
# my $b;
|
||||
# if (defined $self->{bullet}) {
|
||||
# $b = $self->{bullet};
|
||||
# } else {
|
||||
# $b = "UNDEF";
|
||||
# }
|
||||
# $type .= " verbatim: '".($self->{verbatim}||"NONE")."' bullet: '$b' indent: '".($self->{indent}||"NONE")."' type: '".($self->{type}||"NONE")."'";
|
||||
# $type .= " verbatim: '".($self->{verbatim}//"NONE")."' bullet: '$bullets' wrap: '$wrap' indent: '".($self->{indent}//"NONE")."' type: '".($self->{type}//"NONE")."'";
|
||||
# print STDERR "$type\n";
|
||||
|
||||
if ( $bullets and not $wrap and not defined $self->{verbatim} ) {
|
||||
if ( $bullets and not defined $self->{verbatim} ) {
|
||||
|
||||
# Detect bullets
|
||||
# | * blah blah
|
||||
|
@ -803,7 +939,7 @@ sub do_paragraph {
|
|||
# | ^-- aligned
|
||||
# <empty line>
|
||||
#
|
||||
# Other bullets supported:
|
||||
# The leading spaces are optional, and other bullets are supported:
|
||||
# - blah o blah + blah
|
||||
# 1. blah 1) blah (1) blah
|
||||
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).
|
||||
|
||||
=cut
|
||||
|
||||
__END__
|
||||
|
||||
# LocalWords: Charset charset po UTF gettext msgid nostrip GPL
|
||||
|
|
|
@ -11,7 +11,7 @@ use warnings;
|
|||
|
||||
use subs qw(makespace);
|
||||
use vars qw($VERSION @ISA @EXPORT);
|
||||
$VERSION = "0.66";
|
||||
$VERSION = "0.69";
|
||||
@ISA = qw(DynaLoader);
|
||||
@EXPORT = qw(new process translate
|
||||
read write readpo writepo
|
||||
|
@ -544,11 +544,6 @@ of use:
|
|||
($percent,$hit,$queries) = $document->stats();
|
||||
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
|
||||
|
||||
=cut
|
||||
|
@ -573,10 +568,6 @@ sub stats {
|
|||
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
|
||||
|
||||
=over 4
|
||||
|
@ -1186,11 +1177,12 @@ sub encode_from_to {
|
|||
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 {
|
||||
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, "" );
|
||||
foreach my $cursor (@$yamlarray) {
|
||||
|
@ -1205,13 +1197,13 @@ sub handle_yaml {
|
|||
} elsif ( !ref $cursor ) {
|
||||
$self->pushline("---\n");
|
||||
$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
|
||||
} elsif ( ref $cursor eq 'ARRAY' ) {
|
||||
if (@$cursor) {
|
||||
$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 {
|
||||
$self->pushline("---[]\n");
|
||||
}
|
||||
|
@ -1220,7 +1212,7 @@ sub handle_yaml {
|
|||
} elsif ( ref $cursor eq 'HASH' ) {
|
||||
if (%$cursor) {
|
||||
$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 {
|
||||
$self->pushline("--- {}\n");
|
||||
}
|
||||
|
@ -1228,7 +1220,6 @@ sub handle_yaml {
|
|||
} else {
|
||||
die( "Cannot serialize " . ref($cursor) );
|
||||
}
|
||||
$self->pushline("---\n");
|
||||
}
|
||||
|
||||
# Escape the string to make it valid in YAML.
|
||||
|
@ -1262,7 +1253,7 @@ sub handle_yaml {
|
|||
}
|
||||
|
||||
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) {
|
||||
my $header = ( ' ' x $indent ) . '- ';
|
||||
my $type = ref $el;
|
||||
|
@ -1271,14 +1262,14 @@ sub handle_yaml {
|
|||
$self->pushline( $header . YAML::Tiny::_dump_scalar( "dummy", $el, 0 ) . "\n" );
|
||||
} else {
|
||||
$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" );
|
||||
}
|
||||
|
||||
} elsif ( $type eq 'ARRAY' ) {
|
||||
if (@$el) {
|
||||
$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 {
|
||||
$self->pushline( $header . " []\n" );
|
||||
}
|
||||
|
@ -1286,7 +1277,7 @@ sub handle_yaml {
|
|||
} elsif ( $type eq 'HASH' ) {
|
||||
if ( keys %$el ) {
|
||||
$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 {
|
||||
$self->pushline( $header . " {}\n" );
|
||||
}
|
||||
|
@ -1298,28 +1289,38 @@ sub handle_yaml {
|
|||
}
|
||||
|
||||
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 ) {
|
||||
my $el = $hash->{$name};
|
||||
my $header = ( ' ' x $indent ) . YAML::Tiny::_dump_scalar( "dummy", $name, 1 ) . ":";
|
||||
my $type = ref $el;
|
||||
if ( !$type ) {
|
||||
my %keys = %{$yfm_keys};
|
||||
if ( ( not %keys ) || $keys{$name} ) { # either no key is provided, or the key we need is also provided
|
||||
$self->pushline(
|
||||
$header . ' '
|
||||
. format_scalar(
|
||||
$self->translate( $el, $blockref, "YAML Front Matter:$ctx $name", "wrap" => 0 )
|
||||
)
|
||||
. "\n"
|
||||
);
|
||||
my %keys = %{$yfm_keys};
|
||||
my %paths = %{$yfm_paths};
|
||||
my $path = "$ctx $name" =~ s/^\s+|\s+$//gr; # Need to trim the path, at least when there is no ctx yet
|
||||
|
||||
if ( ($el eq 'false') or ($el eq 'true') ) { # Do not translate not quote booleans
|
||||
$self->pushline("$header $el\n");
|
||||
} elsif ( ( scalar %keys > 0 && exists $keys{$name}) or # the key we need is provided
|
||||
( 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 {
|
||||
|
||||
# Work around a bug in YAML::Tiny that quotes numbers
|
||||
# See https://github.com/Perl-Toolchain-Gang/YAML-Tiny#additional-perl-specific-notes
|
||||
if ( Scalar::Util::looks_like_number($el) ) {
|
||||
$self->pushline("$header $el\n");
|
||||
} elsif ( $el =~ /^\[.*\]$/ ) { # Do not quote the lists either
|
||||
$self->pushline("$header $el\n");
|
||||
} else {
|
||||
$self->pushline( $header . ' ' . YAML::Tiny::_dump_scalar( "dummy", $el ) . "\n" );
|
||||
}
|
||||
|
@ -1328,7 +1329,7 @@ sub handle_yaml {
|
|||
} elsif ( $type eq 'ARRAY' ) {
|
||||
if (@$el) {
|
||||
$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 {
|
||||
$self->pushline( $header . " []\n" );
|
||||
}
|
||||
|
@ -1336,7 +1337,7 @@ sub handle_yaml {
|
|||
} elsif ( $type eq 'HASH' ) {
|
||||
if ( keys %$el ) {
|
||||
$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 {
|
||||
$self->pushline( $header . " {}\n" );
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ sub read {
|
|||
my $tmp_filename;
|
||||
( undef, $tmp_filename ) = File::Temp::tempfile(
|
||||
"po4aXXXX",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
SUFFIX => ".xml",
|
||||
OPEN => 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.
|
||||
|
||||
"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
|
||||
particular, tables are getting no testing whatsoever, as we don't use them.
|
||||
However, YMMV: please let me know if something doesn't work for you.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
|
|
@ -1071,7 +1071,7 @@ sub CDATA_trans {
|
|||
sub tag_break_alone {
|
||||
my ( $self, @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;
|
||||
} else {
|
||||
return 1;
|
||||
|
@ -1701,140 +1701,16 @@ sub treat_content {
|
|||
# Append or remove the opening/closing tag from the tag path
|
||||
if ( $tag_types[$type]->{'end'} eq "" ) {
|
||||
if ( $tag_types[$type]->{'beginning'} eq "" ) {
|
||||
|
||||
# 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;
|
||||
}
|
||||
$self->treat_content_open_tag(\@tag, \@paragraph, \@text);
|
||||
} elsif ( $tag_types[$type]->{'beginning'} eq "/" ) {
|
||||
|
||||
# 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'} };
|
||||
}
|
||||
$self->treat_content_close_tag(\@tag, \@paragraph, \@text);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
@ -1908,6 +1784,174 @@ sub treat_content {
|
|||
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).
|
||||
# The $translate argument indicates if the strings must be translated or
|
||||
# just pushed
|
||||
|
|
|
@ -4,140 +4,6 @@
|
|||
# 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
|
||||
|
||||
=head1 NAME
|
||||
|
@ -163,7 +29,7 @@ These are this module's particular options:
|
|||
=item B<keys>
|
||||
|
||||
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
|
||||
matched by at least one of the options.
|
||||
Arrays values are always returned unless the B<skip_array> option is
|
||||
|
@ -172,7 +38,7 @@ provided.
|
|||
=item B<paths>
|
||||
|
||||
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
|
||||
matched by at least one of the options.
|
||||
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
|
||||
|
||||
Copyright © 2017 Brian Exelbierd.
|
||||
Copyright © 2022 Martin Quinson <mquinson#debian.org>.
|
||||
|
||||
This program is free software; you may redistribute it and/or modify it
|
||||
under the terms of GPL (see the COPYING file).
|
||||
|
||||
=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
|
||||
my ($pofile);
|
||||
(undef,$pofile)=File::Temp::tempfile("po4aXXXX",
|
||||
DIR => "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
SUFFIX => ".po",
|
||||
OPEN => 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
|
||||
project.
|
||||
|
||||
When you run the B<po4a> program for the first time, with only a
|
||||
configuration file and the documents to translate (called master
|
||||
documents), it produces a POT file (also called translation template)
|
||||
that contains all of the translatable strings in the document in a form
|
||||
that eases the work of translators.
|
||||
|
||||
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
|
||||
Upon execution, B<po4a> parses all documentation files specified in its
|
||||
configuration file. It updates the PO files (containing the translation) to
|
||||
reflect any change to the documentation, and produce a translated documentation
|
||||
by injecting the content's translation (found in the PO files) into the
|
||||
structure of the original master document.
|
||||
|
||||
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 ---+---->-------->---------+
|
||||
(doc authoring) | |
|
||||
V (po4a executions) >-----+--> translations
|
||||
| | |
|
||||
V (po4a executions) >-----+--> translated
|
||||
| | | documents
|
||||
existing PO files -->--> updated PO files >-+ |
|
||||
^ | |
|
||||
| V |
|
||||
|
@ -72,13 +53,100 @@ are too incomplete may be troubling for the end users.
|
|||
|
|
||||
addendum -->--------------------------------------+
|
||||
|
||||
The master documents are authored by the documentation writers. Any changes are
|
||||
automatically reflected by po4a in the PO files, that are then updated by the
|
||||
translators. All changes to the PO files (either manual or by po4a) are
|
||||
automatically reflected in translated documents. You can mimic this behavior
|
||||
using the L<po4a-updatepo(1)> and L<po4a-translate(1)> scripts in makefiles, but
|
||||
this quickly becomes bothersome and repetitive (see L<po4a(7)>). It is highly
|
||||
recommended to use the B<po4a> program in your build process.
|
||||
The workflow of B<po4a> is asynchronous, as suited to open-source projects. The
|
||||
documentation writers author the master documents at their own pace. The
|
||||
translators review and update the translations in the PO files. The maintainers
|
||||
rerun B<po4a> on need, to reflect any change to the original documentation to
|
||||
the PO files, and to produce updated documentation translations, by injecting
|
||||
the latest translation into the latest document structure.
|
||||
|
||||
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
|
||||
|
||||
|
@ -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.
|
||||
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.
|
||||
|
||||
=item B<--master-language>
|
||||
|
@ -300,7 +368,7 @@ Note: B<$lang> will be extended to the current language.
|
|||
=item B<--no-previous>
|
||||
|
||||
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>
|
||||
|
||||
|
@ -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
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
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
|
||||
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
|
||||
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. 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_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/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
|
||||
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
|
||||
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.
|
||||
|
||||
=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>
|
||||
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
|
||||
|
||||
L<po4a-gettextize(1)>,
|
||||
L<po4a-normalize(1)>,
|
||||
L<po4a-translate(1)>,
|
||||
L<po4a-updatepo(1)>,
|
||||
L<po4a(7)>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Denis Barbier <barbier@linuxfr.org>
|
||||
Nicolas Francois <nicolas.francois@centraliens.net>
|
||||
Nicolas François <nicolas.francois@centraliens.net>
|
||||
Martin Quinson (mquinson#debian.org)
|
||||
|
||||
=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
|
||||
under the terms of GPL (see the COPYING file).
|
||||
|
@ -1119,15 +1133,16 @@ while (<CONFIG>) {
|
|||
next unless defined $basedir;
|
||||
my $candidate = "$basedir/$po_directory";
|
||||
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,
|
||||
$candidate
|
||||
or die wrap_ref_mod( "$config_file:$nb", "", gettext("Cannot list directory '%s' in '%s' "),
|
||||
$po_directory, $basedir );
|
||||
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) {
|
||||
|
@ -1431,7 +1446,12 @@ if ( $pot_filename =~ m/\$master/ ) {
|
|||
|
||||
if ( not scalar @{ $po4a_opts{"partial"} } ) {
|
||||
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
|
||||
# than the POT.
|
||||
|
@ -1535,7 +1555,7 @@ if ($update_pot_file) {
|
|||
if ( $po4a_opts{"split"} ) {
|
||||
( undef, $pot_filename ) = File::Temp::tempfile(
|
||||
"po4a-temp-pot-XXXX",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
SUFFIX => ".pot",
|
||||
OPEN => 0,
|
||||
UNLINK => 0
|
||||
|
@ -1583,7 +1603,7 @@ if ( $po4a_opts{"split"} ) {
|
|||
unless ( $po4a_opts{"force"} ) {
|
||||
( undef, $tmp_file ) = File::Temp::tempfile(
|
||||
"po4aXXXX",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
SUFFIX => ".pot",
|
||||
OPEN => 0,
|
||||
UNLINK => 0
|
||||
|
@ -1616,7 +1636,7 @@ if ( $po4a_opts{"split"} ) {
|
|||
my $tmp_bigpo;
|
||||
( undef, $tmp_bigpo ) = File::Temp::tempfile(
|
||||
"po4aXXXX",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
SUFFIX => "-$lang.po",
|
||||
OPEN => 0,
|
||||
UNLINK => 0
|
||||
|
@ -1705,7 +1725,7 @@ if ( not $po4a_opts{"no-update"} ) {
|
|||
# updated (unless --force was specified).
|
||||
( undef, $tmp_file ) = File::Temp::tempfile(
|
||||
"po4aXXXX",
|
||||
DIR => $ENV{TMPDIR} || "/tmp",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
SUFFIX => ".po",
|
||||
OPEN => 0,
|
||||
UNLINK => 0
|
||||
|
@ -1990,3 +2010,6 @@ sub is_older {
|
|||
}
|
||||
|
||||
__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
|
||||
|
||||
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)
|
||||
|
||||
|
@ -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
|
||||
L<po4a(7)> for a gentle introduction to this project.
|
||||
|
||||
The B<po4a-gettextize> script is in charge of converting documentation files into
|
||||
PO files. You only need it to setup your translation project with po4a, never afterward.
|
||||
The B<po4a-gettextize> script helps you converting your previously existing
|
||||
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
|
||||
strings from the documentation and write a POT file. If you provide a previously
|
||||
existing translated file with the B<-l> flag, B<po4a-gettextize> will try to use
|
||||
the translations that it contains in the produced PO file. This process remains
|
||||
tedious and manual, as explained in Section 'Converting a manual translation to
|
||||
po4a' below.
|
||||
You must provide both a master file (e.g., the source in English) and an
|
||||
existing translated file (e.g., a previous translation attempt without po4a). If
|
||||
you provide more than one master or translation files, they will be used in
|
||||
sequence, but it may be easier to gettextize each page or chapter separately and
|
||||
then use B<msgmerge> to merge all produced PO files. As you wish.
|
||||
|
||||
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
|
||||
PO will use the encoding of the translated input document, or UTF-8 if no
|
||||
translated document is provided.
|
||||
be in UTF-8. If the master document is completely in ASCII, the generated
|
||||
PO will use the encoding of the translated input document.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
|
@ -79,8 +80,8 @@ catalog will be written to the standard output.
|
|||
=item B<-o>, B<--option>
|
||||
|
||||
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
|
||||
example, you could pass '-o tablecells' to the AsciiDoc parser, while the
|
||||
plugin for more information about the valid options and their meanings. For
|
||||
example, you could pass '-o tablecells' to the AsciiDoc parser, while the
|
||||
text parser would accept '-o tabs=split'.
|
||||
|
||||
=item B<-h>, B<--help>
|
||||
|
@ -91,6 +92,11 @@ Show a short help message.
|
|||
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
B<po4a-gettextize> will try to extract the content of any provided translation
|
||||
file, and use this content as msgstr in the produced PO file. Be warned that
|
||||
this process is very fragile: the Nth string of the translated file is supposed
|
||||
to be the translation of the Nth string in the original. This will naturally not
|
||||
work unless both files share exactly the same structure.
|
||||
B<po4a-gettextize> synchronizes the master and localized files to extract their
|
||||
content into a PO file. The content of the master file gives the B<msgid> while
|
||||
the content of the localized file gives the B<msgstr>. This process is somewhat
|
||||
fragile: the Nth string of the translated file is supposed to be the translation
|
||||
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
|
||||
strings. This is how desynchronization are detected during the gettextization.
|
||||
For example, if the files have the following structure, it is very unlikely that
|
||||
the 4th string in translation (of type 'chapter') is the translation of the 4th
|
||||
string in original (of type 'paragraph'). It is more likely that a new
|
||||
paragraph was added to the original, or that two original paragraphs were merged
|
||||
together in the translation.
|
||||
In the example depicted below, it is very unlikely that the 4th string in
|
||||
translation (of type 'chapter') is the translation of the 4th string in original
|
||||
(of type 'paragraph'). It is more likely that a new paragraph was added to the
|
||||
original, or that two original paragraphs were merged together in the
|
||||
translation.
|
||||
|
||||
Original Translation
|
||||
|
||||
|
@ -148,73 +159,57 @@ together in the translation.
|
|||
chapter paragraph
|
||||
paragraph paragraph
|
||||
|
||||
B<po4a-gettextize> will verbosely diagnose any detected structure
|
||||
desynchronization. When this happens, you should manually edit the files (this
|
||||
probably requires that you have some notions of the target language). You must
|
||||
add fake paragraphs or remove some content in one of the documents (or both) to
|
||||
fix the reported disparities, until the structure of both documents perfectly
|
||||
match. Some tricks are given in the next section.
|
||||
B<po4a-gettextize> will verbosely diagnose any structure desynchronization. When
|
||||
this happens, you should manually edit the files to add fake paragraphs or
|
||||
remove some content here and there until the structure of both files actually
|
||||
match. Some tricks are given below to salvage the most of the existing
|
||||
translation while doing so.
|
||||
|
||||
Even when the document is successfully processed, undetected disparities and
|
||||
silent errors are still possible. That is why any translation associated
|
||||
automatically by po4a-gettextize is marked as I<fuzzy> to require an manual
|
||||
inspection by humans. One has to check that each retrieved msgstr is actually
|
||||
the translation of the associated msgid, and not the string before or after.
|
||||
If you are lucky enough to have a perfect match in the file structures out of
|
||||
the box, building a correct PO file is a matter of seconds. Otherwise, you will
|
||||
soon understand why this process has such an ugly name :) Even so,
|
||||
gettextization often remains faster than translating everything again. I
|
||||
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
|
||||
translated document and in the original one. The best is to do the
|
||||
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.
|
||||
After a successful gettextization, the produced documents should be manually
|
||||
checked for undetected disparities and silent errors, as explained below.
|
||||
|
||||
If you are lucky enough to have a a perfect match in the file structures,
|
||||
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.
|
||||
=head3 Hints and tricks for the gettextization process
|
||||
|
||||
Even when things go wrong, gettextization often remains faster than translating
|
||||
everything again. I was able to gettextize the existing French translation of
|
||||
the whole Perl documentation in one day, even though the structure of many
|
||||
documents were desynchronized. That was more than two megabytes of original text
|
||||
(2 millions of characters): restarting the translation from scratch would have
|
||||
required several months of work.
|
||||
The gettextization stops as soon as a desynchronization is detected. When this
|
||||
happens, you need to edit the files as much as needed to re-align the files'
|
||||
structures. B<po4a-gettextize> is rather verbose when things go wrong. 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.
|
||||
|
||||
=head2 Hints and tricks for the gettextization process
|
||||
|
||||
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:
|
||||
Here are some tricks to help you in this tedious process and ensure that you
|
||||
salvage the most of the previous translation:
|
||||
|
||||
=over
|
||||
|
||||
=item
|
||||
|
||||
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
|
||||
(see L<po4a(7)>).
|
||||
to the translators. They should be added separately to B<po4a> as addendas (see
|
||||
L<po4a(7)>).
|
||||
|
||||
=item
|
||||
|
||||
If you need to edit the files to align their structures, you should prefer
|
||||
editing the translation if possible. Indeed, if the changes to the original are
|
||||
too intrusive, the old and new versions will not be matched during the PO
|
||||
update, and the corresponding translation will be dumped anyway. But do not
|
||||
hesitate to also edit the original document if required: the important thing is
|
||||
to get a first PO file to start with.
|
||||
When editing the files to align their structures, prefer editing the translation
|
||||
if possible. Indeed, if the changes to the original are too intrusive, the old
|
||||
and new versions will not be matched during the first po4a run after
|
||||
gettextization (see below). Any unmatched translation will be dumped anyway.
|
||||
That being said, you still want to edit the original document if it's too hard
|
||||
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
|
||||
|
||||
|
@ -225,9 +220,11 @@ when synchronizing the PO file with the document.
|
|||
=item
|
||||
|
||||
You should probably inform the original author of any structural change in the
|
||||
translation that seems justified. Issues in the original document should reported
|
||||
to the author. Fixing them in your translation only fixes them for a part of the
|
||||
community. Plus, it is impossible to do so when using po4a ;)
|
||||
translation that seems justified. Issues in the original document should
|
||||
reported to the author. Fixing them in your translation only fixes them for a
|
||||
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
|
||||
|
||||
|
@ -247,48 +244,74 @@ line and the content of the item.
|
|||
Sometimes, the desynchronization message seems odd because the translation is
|
||||
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
|
||||
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
|
||||
|
||||
In some unfortunate settings, you will get the feeling that po4a ate some parts
|
||||
of the text, either the original or the translation. F<gettextization.failed.po>
|
||||
indicates that both files matched as expected up to the paragraph N. But then,
|
||||
an (unsuccessful) attempt is made to match the N+1 paragraph in the original
|
||||
file not with the N+1 paragraph in the translation as it should, but with the
|
||||
N+2 paragraph. Just as if the N+1 paragraph that you see in the document simply
|
||||
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.
|
||||
Other issues may come from duplicated strings in either the original or
|
||||
translation. Duplicated strings are merged in PO files, with two references.
|
||||
This constitutes a difficulty for the gettextization algorithm, that is a simple
|
||||
one to one pairing between the B<msgid>s of both the master and the localized
|
||||
files. It is however believed that recent versions of po4a deal properly with
|
||||
duplicated strings, so you should report any remaining issue that you may encounter.
|
||||
|
||||
=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
|
||||
|
||||
L<po4a(1)>,
|
||||
|
@ -300,12 +323,12 @@ L<po4a(7)>.
|
|||
=head1 AUTHORS
|
||||
|
||||
Denis Barbier <barbier@linuxfr.org>
|
||||
Nicolas Francois <nicolas.francois@centraliens.net>
|
||||
Nicolas François <nicolas.francois@centraliens.net>
|
||||
Martin Quinson (mquinson#debian.org)
|
||||
|
||||
=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
|
||||
under the terms of GPL (see the COPYING file).
|
||||
|
@ -324,8 +347,170 @@ use Locale::Po4a::Common;
|
|||
|
||||
use Pod::Usage qw(pod2usage);
|
||||
|
||||
our %debug = (
|
||||
'encoding' => 0,
|
||||
);
|
||||
|
||||
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 {
|
||||
Locale::Po4a::Common::show_version("po4a-gettextize");
|
||||
exit 0;
|
||||
|
@ -341,12 +526,13 @@ my %opts = (
|
|||
);
|
||||
|
||||
my ($pofile) = ('-');
|
||||
my ( @masterfile, @locfile, $help_fmt, $help, $type, @options );
|
||||
my ( @masterfile, @locfile, $help_fmt, $help, $keep_temps, $type, @options );
|
||||
my ( $mastchar, $locchar );
|
||||
Getopt::Long::config( 'bundling', 'no_getopt_compat', 'no_auto_abbrev' );
|
||||
GetOptions(
|
||||
'help|h' => \$help,
|
||||
'help-format' => \$help_fmt,
|
||||
'help|h' => \$help,
|
||||
'help-format' => \$help_fmt,
|
||||
'keep-temps|k' => \$keep_temps,
|
||||
|
||||
'master|m=s' => \@masterfile,
|
||||
'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
|
||||
foreach my $file ( @masterfile, @locfile ) {
|
||||
$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
|
||||
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
|
||||
# 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
|
||||
$mastertt->writepo($pofile);
|
||||
} 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);
|
||||
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;
|
||||
|
||||
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__
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue