DBD::PO - DBI driver for PO files
$Id: PO.pm 434 2010-01-24 13:15:34Z steffenw $
$HeadURL: https://dbd-po.svn.sourceforge.net/svnroot/dbd-po/trunk/DBD-PO/lib/DBD/PO.pm $
2.10
use Carp qw(croak); use DBI (); use Socket qw($LF); # The next line is mostly obsolete # and was introduced for performance settings only. require DBD::PO; DBD::PO->init(qw(...)); my $dbh = DBI->connect( 'DBI:PO:' . 'f_dir=dir_x;' # optional: # The default database is './', # here set to the directory 'dir_x'. # The default value is often unuseful. . "po_separator=\n;" # optional: # The default 'po_separator' to set/get # concatinated data is "\n", # here set to "\n" unnecessary. # The default value is mostly useful # because the internal representation # of line ending is \n (Windows too). # This is different for binary IO. . "po_eol=$LF;" # optional: # The default 'po_eol' (po end of line) # is network typical like 'use Socket qw($CRLF)', # here set to $LF like 'use Socket qw($LF)'. # The default value is mostly useful. . 'po_charset=utf-8', # optional: # Write nothing for 'iso-8859-1' files # and use bytes internal. # (It is not a good idea.) # Write 'utf-8' for 'utf-8' files # and use unicode chars internal. # Write 'iso-8859-1' for 'iso-8859-1' files # and use unicode chars internal # and so on for other charsets. # The default value is mostly not useful. undef, # Username is not used. undef, # Password is not used. { RaiseError => 1, # The easy way to handle exceptions. PrintError => 0, # The easy way to handle exceptions as warnings. }, ) or croak 'Cannot connect: ' . DBI->errstr();
Note that no column names will be stored. They are fixed. Thus all other information including column type (INTEGER or CHAR(x), for example), column attributes (NOT NULL, PRIMARY KEY, ...) will silently be discarded.
Table names cannot be arbitrary, due to restrictions of the SQL syntax. I recommend that table names are valid SQL identifiers: The first character is alphabetic, followed by an arbitrary number of alphanumeric characters. If you want to use other files, the file names must start with '/', './' or '../' and they must not contain white space.
For conditional execution use CREATE TABLE IF EXISTS statement.
Columns:
msgid
The text to translate (emty string for header).
The 'msgid' can contain Locale::Maketext placeholders. They have to be stored in gettext format. To change the format, use the database handle function 'maketext_to_gettext'.
msgstr
The translation.
The 'msgid' can contain Locale::Maketext placeholder. They have to be stored in gettext format. To change the format, use the database handle function 'maketext_to_gettext'.
comment
The translator comment text concatinated by 'po_separator'.
automatic
The automatic comment text concatinated by 'po_separator'.
reference
Where the text to translate is from, concatinated by 'po_separator'.
msgctxt
This is the context.
fuzzy
The translation is finished (0) or not (1).
obsolete
The translation is used (0) or not (1).
..._format (...-format, no-...-format)
There are c-format, php-format and so on, see DBD::PO::Locale::PO.
To use these format flags call DBD::PO-init(qw(c-format php-format ...);> or DBD::PO-init(':format');> or DBD::PO-init(':all');> early.
DBD::PO-
Flag, not set (0), set (1) or negative set (-1).
msgid_plural
The same like msgid but for plural.
To use these format flags call DBD::PO-init(':plural');> or DBD::PO-init(':all');> early.
msgstr_0 .. msgstr_5
Insted of msgstr for plural item 0 .. 5.
previous_msgctxt
As comment formatted former msgctxt.
To use these format flags call DBD::PO-init(':previous');> or DBD::PO-init(':all');> early.
previous_msgid
As comment formatted former msgid.
previous_msgid_plural
As comment formatted former msgid_plural.
..._format, msgid_plural, msgstr_0 .. msgstr_5 and previous_... are normally switched off. See method init.
$dbh->do(<<'EOT'); CREATE TABLE table.po ( msgid VARCHAR, msgstr VARCHAR, comment VARCHAR, automatic VARCHAR, reference VARCHAR, msgctxt VARCHAR, fuzzy INTEGER, obsolete INTEGER, ..._format INTEGER, msgid_plural VARCHAR, msgstr_0 VARCHAR, msgstr_1 VARCHAR, msgstr_2 VARCHAR, msgstr_3 VARCHAR, msgstr_4 VARCHAR, msgstr_5 VARCHAR, previous_msgctxt VARCHAR, previous_msgid VARCHAR, previous_msgid_plural VARCHAR ) EOT
The charset will set to the as parameter 'po_charset' given value at the connect method. Note that the default encoding is nothing, not 'utf-8'.
my $header_msgstr = $dbh->func( undef, # function name 'build_header_msgstr', );
my $header_msgstr = $dbh->func( { 'Project-Id-Version' => 'Project name', 'Report-Msgid-Bugs-To-Name' => 'Bug Reporter', 'Report-Msgid-Bugs-To-Mail' => 'report.msgid.bugs.to@example.org', 'POT-Creation-Date' => 'the POT creation date', 'PO-Revision-Date' => 'the PO revision date', 'Last-Translator-Name' => 'Steffen Winkler', 'Last-Translator-Mail' => 'steffenw@example.org', 'Language-Team-Name' => 'MyTeam', 'Language-Team-Mail' => 'cpan@example.org', # Do not set the following values. # They will be set automaticly. 'MIME-Version' => '1.0', 'Content-Type' => 'text/plain', charset => $po_charset || 'iso-8859-1', 'Content-Transfer-Encoding' => '8bit', # an English/German example 'Plural-Forms' => 'nplurals=2; plural=n != 1;', # place here pairs for extra parameters extended => [qw( X-Poedit-Language German X-Poedit-Country GERMANY X-Poedit-SourceCharset utf-8 )], }, # function name 'build_header_msgstr', );
Write the header row always at first!
use Socket qw($CRLF); my $separator = $CRLF; # But it is more easy # to use the po_separator default \n # and than the join is obsolete # because the strings typical including \n. my $header_comment = join( $separator, 'This is a translator comment for the header.', 'And this is line 2 of.', ); $dbh->do(<<'EOT', undef, $header_comment, $header_msgstr); INSERT INTO table.po ( comment, msgstr ) VALUES (?, ?) EOT
my $sth = $dbh->prepare(<<'EOT'); INSERT INTO table.po ( msgid, msgstr, reference ) VALUES (?, ?, ?) EOT $sth->execute( join( $separator, 'text to translate', '2nd line of text', ), join( $separator, 'translation', '2nd line of translation', ), join( $separator, 'my_program: 17', 'my_program: 269', ), );
my $sth = $dbh->prepare(<<'EOT'); INSERT INTO table.po ( msgid, msgstr, reference ) VALUES (?, ?, ?) EOT $sth->execute( $dbh->func( # mapping: # - scalar to scalar # - or array to array # - here 2 values given to 2 returns join( $separator, 'text to translate', '2nd line of text', ), join( $separator, 'translation', '2nd line of translation', ), 'maketext_to_gettext', ), join( $separator, 'my_program: 17', 'my_program: 269', ), );
Scalar to scalar mapping.
my $charset = $dhh->func( {table => 'table_name'}, 'charset', 'get_header_msgstr_data', );
Arrayref to arrayref mapping.
my $array_ref = $dbh->func( {table => 'table_name'}, [qw(charset Project-Id-Version)], 'get_header_msgstr_data', ); my ($charset, $project_id_version) = @{$array_ref};
$sth = $dbh->prepare(<<'EOT'); SELECT msgstr FROM table.po WHERE msgid = ? EOT $sth->execute( join( $separator, 'text to translate', '2nd line of text', ), ); my ($msgstr) = $sth->fetchrow_array();
$dbh->do(<<'EOT'); UPDATE table.po SET msgstr = '', fuzzy = 1 WHERE msgid = 'my_id' EOT
$dbh->do(<<'EOT'); DELETE FROM table.po WHERE obsolete = 1 EOT
For conditional execution use DROP TABLE IF EXISTS statement.
$dbh->do(<<'EOT'); DROP TABLE table.po EOT
$dbh->disconnect();
In case of join tables, SQL::Statement does not allow a file suffix.
File suffix can be used here:
SELECT msgstr FROM de.po WHERE msgid <> ''
But not here:
SELECT de.po.msgstr, ru.po.msgstr FROM de.po INNER JOIN ru.po ON de.po.msgid = ru.po.msgid WHERE de.po.msgid <> ''
Set a mapping hash like:
$dbh->{po_tables}->{'de'} = {file => 'de.po'}; $dbh->{po_tables}->{'ru'} = {file => 'ru.po'};
Do not write the suffix now:
SELECT de.msgstr, ru.msgstr FROM de INNER JOIN ru ON de.msgid = ru.msgid WHERE de.msgid <> ''
or the same here:
SELECT msgstr FROM de WHERE msgid <> ''
The DBD::PO module is yet another driver for the DBI (Database independent interface for Perl). This one is based on the SQL 'engine' SQL::Statement and the abstract DBI driver DBD::File and implements access to so-called PO files (GNU gettext). Such files are readable by Locale::Maketext.
See DBI for details on DBI, SQL::Statement for details on SQL::Statement and DBD::File for details on the base class DBD::File.
--------------------- | DBI | --------------------- | --------------------- ----------- --------------- | DBD::PO |---| DBD::File |---| SQL-Statement | --------------------- ----------- --------------- | --------------------- | DBD::PO::Text::PO | --------------------- | --------------------- | DBD::PO::Locale::PO | --------------------- | table_file.po
Inside of this Distribution is a directory named example. Run this *.pl files.
DBD::PO->init(...);
This is a class method to optimize the size of arrays. The default settings are performant.
Do not call this method during you have an active connection!
Parameters:
:plural
Allow all plural forms.
:format
Allow all format flags.
:all
Allow all.
c-format as example
Allow the format flag 'c-format'. For all the other format flags see DBD::PO::Locale::PO.
allow_lost_blank_lines
If no blank line is between PO entrys inside of the PO file, this switch allows to read the damaged file.
Use this method to show all header data for debugging.
$all_header_keys_ref = DBD::PO->get_all_header_keys(); my $header_data_ref = $dbh->func( {table => $table}, # wich table $all_header_keys_ref, # what to get 'get_header_msgstr_data', # function name );
or
$all_header_keys_ref = $dbh->func( 'get_all_header_keys', # function_name ); my $header_data_ref = $dbh->func( {table => $table}, # wich table $all_header_keys_ref, # what to get 'get_header_msgstr_data', # function name );
see DBI
Carp
Socket
parent
DBI
SQL::Statement
Params::Validate
The only system dependent feature that DBD::File uses, is the flock() function. Thus the module should run (in theory) on any system with a working flock(), in particular on all Unix machines and on Windows NT. Under Windows 95 and MacOS the use of flock() is disabled, thus the module should still be usable,
flock()
Unlike other DBI drivers, you don't need an external SQL engine or a running server. All you need are the following Perl modules, available from any CPAN mirror.
The level of SQL support available depends on the version of SQL::Statement installed. Any version will support *basic* CREATE, INSERT, DELETE, UPDATE, and SELECT statements. Only versions of SQL::Statement 1.0 and above support additional features such as table joins, string functions, etc. See the documentation of the latest version of SQL::Statement for details.
not known
The module is using flock() internally. However, this function is not available on platforms. Using flock() is disabled on MacOS and Windows 95: There's no locking at all (perhaps not so important on these operating systems, as they are for single users anyways).
DBD::File as base class
SQL::Statement and SQL::Statement::Syntax as Parser
Locale::PO has bugs, more than documented
DBD::CSV my guideline
http://www.gnu.org/software/gettext/manual/gettext.html
http://en.wikipedia.org/wiki/Gettext
http://translate.sourceforge.net/wiki/l10n/pluralforms
http://rassie.org/archives/247 The choice of the right module for the translation.
Locale::Maketext::Lexicon see xgettext.pl
Steffen Winkler
Copyright (c) 2008 - 2010, Steffen Winkler <steffenw at cpan.org>. All rights reserved.
<steffenw at cpan.org>
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install DBD::PO, copy and paste the appropriate command in to your terminal.
cpanm
cpanm DBD::PO
CPAN shell
perl -MCPAN -e shell install DBD::PO
For more information on module installation, please visit the detailed CPAN module installation guide.