TimeTrex Community Edition v16.2.0

This commit is contained in:
2022-12-13 07:10:06 +01:00
commit 472f000c1b
6810 changed files with 2636142 additions and 0 deletions

214
tools/i18n/README.i18n Normal file
View File

@ -0,0 +1,214 @@
TimeTrex Message Internationalization(i18n) README
by Open Source Consulting, S.A.
= OVERVIEW =
TimeTrex contains english strings embedded throughout the PHP code and
smarty templates. The GNU Gettext suite of tools has been chosen to aid
with the tasks of:
- marking and extracting english strings from the source files
- translating english strings into other languages
- displaying the foreign language translations of the strings
- merging in new english strings from the source files
- merging in new translations from the translators
It is a very good idea for anyone working in this area to read up more
about gettext here:
http://www.gnu.org/software/gettext/
Below, we will explain more about how gettext is integrated with TimeTrex,
how to properly code strings for translation, and how the translation
maintenance tools work.
= TTi18n Class =
TimeTrex now includes a class for handling all i18n related matters.
Methods related to message translation include:
- chooseBestLocale() -- determines which locale to use for messages.
- gettext() -- returns a translated version of given input string.
This class works basically like the standard setlocale(),
bindtextdomain(), gettext() combination but it allows us to abstract the
implementation a bit. For example, we may use PEAR's Translation2 class
to parse the gettext files, instead of using PHP's native gettext()
function.
For this reason, it is important that all translation calls in the system
go through TTi18n::gettext() instead of calling gettext() directly.
= Smarty Template Files =
We are using a slightly modified version of the gettext plugin for smarty.
This plugin allows us to mark strings for translation with the following
syntax:
{t}Here is some text that needs to be translated.{/t}
The only modification to this plugin is that we call TTi18n::gettext()
(when defined) instead of gettext().
= PHP Source Code Files =
Any strings within the source code that...
a) contain words and
b) are intended for an end-user to see
...must be embedded within a call to TTi18n::gettext( "my string" ).
There are two reasons for this:
1) gettext() must be called in order to perform the translation at
runtime. This should be obvious.
2) The string extractor looks for "gettext( ... )" to know which strings
to extract. Therefore, the following code is to be avoided:
$myvar = 'Please enter a value below';
$myvar = TTi18n::gettext( $myvar );
While the above would do the right thing at runtime, the extractor
would not know that this string represents english, so the above
string would probably never get translated. Instead, this should be
coded as:
$myvar = TTi18n::gettext('Please enter a value below');
Be careful to ensure that gettext() is only called once on a given string.
Calling multiple times will probably not cause display problems, but each
call adds some performance overhead.
= The locale directories and messages.po files =
The locale directory exists at
timetrex/interface/locale
This directory contains:
- the messages.pot master string dictionary with all english strings.
- a sub-directory for each locale, eg es_ES for spanish/Spain.
- the locale_stats.txt file which contains statistics about translations.
Each locale sub-directory contains another sub-directory LC_MESSAGES which
in turn contains messages.po and (possibly) messages.mo. messages.po will
contain the translations for that particular locale. messages.mo is a
compiled form of the .po file that is necessary for GNU gettext to
function -- however, it is not always required when using the Translation2
library.
*** IMPORTANT ***
In the interest of avoiding possible encoding headaches, we are
standardizing on the use UTF-8 encoded messages.po files. That is, all
messages.po should be saved as UTF-8 before they are placed/updated into
the tree.
Why? It has been observed that the Translation2 library does not properly
convert encodings. While it may be possible to work around this, UTF-8 makes
things simple all around.
= The Translation helper tools =
These files live in tools/i18n. ( Though they could be anywhere. )
Each of these should be run from the directory in which it is saved.
mklocales.php
This script creates and initializes the locale directories beneath the
interface/locale directory. Edit the script and re-run to add a new
locale directory and associated messages.po file.
gen_master_pot.sh
This file generates a master messages.pot file in the interface/locale
directory. This file is then used as the source when merging to
individual locales.
mergelocale.sh
This script merges new strings from messages.pot master file into a
messages.po file for a single locale. It also generates the binary
messages.mo file. Typically, this script is only called by mergelocales.sh
mergelocales.php
This script merges new strings from message.pot master file into the
messages.po files for all existings locale directories, creates the
binary messages.mo files, and updates the translation stats.
calc_l10n_stats.php
This script calculates the percentage of the application that has been
translated for each available locale. It writes out a csv file that can
be read by a PHP script to display the stats on a web page.
notify_translator.php
This file notifies the translator by e-mail when new source
strings are available for TimeTrex. Be careful not to run this by
accident, as you may end up spamming people unnecessarily.
tsmarty2c.php
This script is part of the smarty gettext plugin, and is used to extract
the strings that can be translated from the smarty templates. This
script is called by the gen_master_pot.sh script.
updatetranslation.sh
This script is used to merge a single messages.po file
provided by a translator with the corresponding messages.po files within
TimeTrex.
= Using the translation helper tools on a daily basis =
These are the typical events that happen during application development:
1) New strings get added into the PHP source or smarty templates.
2) A translator sent in new translations.
3) We need to add a new locale (language) for translation.
Let's look at them individually:
1) New strings get added into the PHP source or smarty templates.
In this case, we need to a) update the master .pot file, b) merge
those changes into the indvidual messages.po files, c) generate the binary
messages.mo files and d) update the locale stats. It is as simple as:
$ ./gen_master_pot.sh
$ ./mergelocales.php
2) A translator sent in new translations.
Here, we just need to merge the translator's changes into a single
messages.po file for a single locale. Then we want to update the binary
message.mo file and the locale stats. Let's suppose we have just received
spanish translations ( es_ES ) and have saved them in /tmp/messages.po.
$ ./update_translation.sh es_ES /tmp/messages.po
$ ./calc_l10n_stats.php
3) We need to add a new locale (language) for translation.
Let's suppose we have found an Italian translator, and now we want to add
an it_IT locale. All we do is:
$ vi mklocales.php # Now uncomment the line with // 'it_IT'.
$ ./mklocales.php
We could also make all the known locales by uncommenting all the locale
lines in this script, and then re-running it.

View File

@ -0,0 +1,157 @@
#!/usr/bin/php
<?php
/*********************************************************************************
*
* TimeTrex is a Workforce Management program developed by
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* 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 Affero General Public License for more
* details.
*
*
* You should have received a copy of the GNU Affero General Public License along
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
*
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
*
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by TimeTrex".
*
********************************************************************************/
/*
* File Contributed By: Open Source Consulting, S.A. San Jose, Costa Rica.
* http://osc.co.cr
*/
if ( PHP_SAPI != 'cli' ) {
echo "This script can only be called from the Command Line.\n";
exit;
}
// Calculates percent complete statistics for all locales.
// Must be run from tools/i18n directory.
$root_dir = '../../interface/locale';
if ( count( $argv ) > 1 ) {
$root_dir = $argv[1];
}
$d = opendir( $root_dir );
if ( $d ) {
echo "calculating locale statistics...\n";
$outpath = $root_dir . '/' . 'locale_stats.txt';
$fh = fopen( $outpath, 'w' );
$ignore_dirs = [ '.', '..', 'CVS' ];
while ( false !== ( $file = readdir( $d ) ) ) {
if ( is_dir( $root_dir . '/' . $file ) && !in_array( $file, $ignore_dirs ) ) {
$stats = calcStats( $root_dir, $file );
$pct = $stats['pct_complete'];
$team = $stats['team'];
fwrite( $fh, "$file|$pct|$team\n" );
}
}
closedir( $d );
fclose( $fh );
echo "done. stats saved in $outpath\n";
}
function calcStats( $root_dir, $locale ) {
$messages = 0;
$translations = 0;
$fuzzy = 0;
$team = '';
$path = $root_dir . '/' . $locale . '/LC_MESSAGES/messages.po';
// echo "<li><b>$path</b>";
if ( file_exists( $path ) ) {
$lines = file( $path );
$in_msgid = false;
$in_msgstr = false;
$found_translation = false;
$found_msg = false;
foreach ( $lines as $line ) {
// ignore comment lines
if ( $line[0] == '#' ) {
continue;
}
// Parse out the contributors.
if ( strstr( $line, '"Language-Team: ' ) ) {
$endpos = strpos( $line, '\n' );
if ( $endpos === false ) {
$endpos = strlen( $line ) - 2;
}
$len = strlen( '"Language-Team: ' );
$field = substr( $line, $len, $endpos - $len );
$names = explode( ',', $field );
foreach ( $names as $name ) {
if ( $name != 'none' ) {
if ( $team != '' ) {
$team .= ',';
}
$team .= trim( $name );
}
}
}
if ( strstr( $line, 'msgid "' ) ) {
$in_msgid = true;
$in_msgstr = false;
$found_msg = false;
$found_translation = false;
}
if ( $in_msgid && !$found_msg && strstr( $line, '"' ) && !strstr( $line, '""' ) ) {
// echo "<li>msgid: $line";
$found_msg = true;
$messages++;
} else if ( strstr( $line, 'msgstr "' ) ) {
$in_msgstr = true;
$in_msgid = false;
}
if ( $in_msgstr && $found_msg && !$found_translation ) {
if ( strstr( $line, '"' ) && !strstr( $line, '""' ) ) {
// echo "<li>msgstr: $line";
$translations++;
$found_translation = true;
}
} else if ( strstr( $line, '#, fuzzy' ) ) {
$fuzzy++;
}
}
}
$translations -= $fuzzy;
$pct_complete = $messages ? (int)( ( $translations / $messages ) * 100 ) : 0;
return [ 'pct_complete' => $pct_complete, 'team' => $team ];
}
?>

51
tools/i18n/gen_master_pot.sh Executable file
View File

@ -0,0 +1,51 @@
#!/bin/bash -x
##$License$##
##
# File Contributed By: Open Source Consulting, S.A. San Jose, Costa Rica.
# http://osc.co.cr
##
# This script generates the master .pot file containing english strings
# for translation.
#
# These strings are parsed from:
# * smarty templates between {t}some text{/t} blocks
# * PHP Files containing TTi18n::gettext("some text") function calls.
# We could also parse from static DB text, but so far see no need for
# doing so.
DEPTH=../..
LOCALE_ROOT=$DEPTH/interface/locale
POT_FILENAME=messages.pot
#---- Ensure pot file exists ----
touch $LOCALE_ROOT/$POT_FILENAME
#---- Extract strings from templates ----
#echo "Parsing templates..."
#TMP_FILE=/tmp/gen_master_pot_tmp.txt
#find $DEPTH/templates -name "*.tpl" | grep -v "\.git" | xargs -i php tsmarty2c.php \{\} | xgettext --from-code=UTF-8 --no-wrap --language=C --no-location -s --output-dir=$LOCALE_ROOT -o $POT_FILENAME -
#---- Extract strings from PHP Files ----
# Note that we want to extract from TTi18n::gettext() calls.
# xgettext ignores the "TTi18n::" bit and sees the gettext(). So it works.
# When we removed the SMARTY parsing, also remove --join-existing option as this is now the first parse command that is run.
echo "Parsing PHP Files..."
find $DEPTH/ -name "*.php" | egrep -v "\.git|/templates_c|/vendor" > /tmp/xgettext_php.files
xgettext --from-code=UTF-8 --no-wrap --keyword=getText --language=PHP -s -f /tmp/xgettext_php.files --output-dir=$LOCALE_ROOT -o $POT_FILENAME
rm -f /tmp/xgettext_php.files
echo "Parsing JS Files..."
#find $DEPTH/ -name "*.js" | grep -v "\.git" | xargs cat | sed 's/<br>/ /g' | sed 's/\n/ /g' | xgettext --from-code=UTF-8 --no-wrap --keyword=_ --join-existing --language=Javascript --no-location -s --output-dir=$LOCALE_ROOT -o $POT_FILENAME -
find $DEPTH/ -name "*.js" | egrep -v "\.git|/node_modules|/tools/compile|/interface/html5/framework|/interface/html5/dist" > /tmp/xgettext_js.files
xgettext --from-code=UTF-8 --no-wrap --keyword=_ --join-existing --language=Javascript -s -f /tmp/xgettext_js.files --output-dir=$LOCALE_ROOT -o $POT_FILENAME
rm -f /tmp/xgettext_js.files
#---- Extract strings from DB Tables with static strings ----
### Not necessary for TimeTrex at this time ###
#---- Done ----
echo "Done! POT File is in " $LOCALE_ROOT/$POT_FILENAME

55
tools/i18n/mergelocale.sh Executable file
View File

@ -0,0 +1,55 @@
#!/bin/bash
##$License$##
##
# File Contributed By: Open Source Consulting, S.A. San Jose, Costa Rica.
# http://osc.co.cr
##
# This script is useful for merging latest changes from the master .pot file into
# a given locale file, and then generating the corresponding .mo binary file.
# This script is intended to be run from the tools/i18n directory
# arg1 should be the locale ID
lc=$1
cd ../../interface/locale
#Clear the en_US translation to avoid fuzzy translations, always create it from scratch.
if [ $lc == 'en_US' ] ; then
rm -f $lc/LC_MESSAGES/messages.po
cat << EOF > $lc/LC_MESSAGES/messages.po
# English translation for timetrex
msgid ""
msgstr ""
"Project-Id-Version: timetrex\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: N/A\n"
"Last-Translator: <N/A>\n"
"Language-Team: <N/A>\n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-07-10 17:45+0000\n"
"X-Generator: Launchpad (build 17620)\n"
EOF
fi
if [ $lc == 'yi_US' ] ; then
#This is a test locale, change all strings to something that stands out so we can find untranslated ones easily.
cat $lc/LC_MESSAGES/messages.po | sed -e '15,$s/msgstr ""/msgstr "Z"/g' > $lc/LC_MESSAGES/messages.po.tmp
mv $lc/LC_MESSAGES/messages.po.tmp $lc/LC_MESSAGES/messages.po
fi
#Don't use fuzzy matching with msgmerge to avoid issues with non-translating strings or mixing up of strings.
touch $lc/LC_MESSAGES/messages.po && \
msguniq -u --no-wrap --use-first $lc/LC_MESSAGES/messages.po -o $lc/LC_MESSAGES/messages.po && \
msgmerge -N --no-wrap -s --update $lc/LC_MESSAGES/messages.po ./messages.pot && \
msgfmt -c -o $lc/LC_MESSAGES/messages.mo $lc/LC_MESSAGES/messages.po
#Convert to .JSON file
php ../../tools/i18n/po2json.php -i $lc/LC_MESSAGES/messages.po -o $lc/LC_MESSAGES/messages.json -n i18n_dictionary
rm -f $lc/LC_MESSAGES/messages.po~

37
tools/i18n/mergelocales.sh Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/php
<?php
/*$License$*/
/*
* File Contributed By: Open Source Consulting, S.A. San Jose, Costa Rica.
* http://osc.co.cr
*/
// Merges new strings from messages.pot into messages.po for all
// locales. Also compiles message.mo file, and calculates stats.
$cwd = getcwd();
$path="../../interface/locale/";
$directory = dir($path);
$invalid_dir = array('CVS' => 1, '..' => 2, '.' => 3);
$locales = array();
$index = 0;
while ($arch = $directory->read())
{
if (!isset($invalid_dir[$arch]) && is_dir($path.$arch)){
$locales[$index] = $arch;
$index ++;
}
}
$directory->close();
asort($locales);
foreach ($locales as $locale){
echo $locale;
$cmd = "./mergelocale.sh $locale";
exec($cmd);
}
exec( "php ./calc_l10n_stats.php" );
?>

177
tools/i18n/mklocales.php Normal file
View File

@ -0,0 +1,177 @@
#!/usr/bin/php
<?php
/*********************************************************************************
*
* TimeTrex is a Workforce Management program developed by
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* 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 Affero General Public License for more
* details.
*
*
* You should have received a copy of the GNU Affero General Public License along
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
*
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
*
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by TimeTrex".
*
********************************************************************************/
/*
* File Contributed By: Open Source Consulting, S.A. San Jose, Costa Rica.
* http://osc.co.cr
*/
if ( PHP_SAPI != 'cli' ) {
echo "This script can only be called from the Command Line.\n";
exit;
}
// creates the locale directories for use with gettext
// and also initializes each with a messages.po file.
// Must be run from the i18n tools directory
//
$depth = '../..';
$locales = [
// 'af_ZA',
// 'am_ET',
'ar_EG',
// 'as_IN',
// 'az_AZ',
// 'be_BY',
// 'bg_BG',
// 'bn_IN',
// 'bo_CN',
// 'br_FR',
// 'bs_BA',
// 'ca_ES',
// 'ce_RU',
// 'co_FR',
// 'cs_CZ',
// 'cy_GB',
'da_DK',
'de_DE',
// 'dz_BT',
// 'el_GR',
'en_US',
'es_ES',
// 'et_EE',
// 'fa_IR',
// 'fi_FI',
// 'fj_FJ',
// 'fo_FO',
'fr_FR',
'fr_CA',
// 'ga_IE',
// 'gd_GB',
// 'gu_IN',
// 'he_IL',
// 'hi_IN',
// 'hr_HR',
'hu_HU',
// 'hy_AM',
'id_ID',
// 'is_IS',
'it_IT',
// 'ja_JP',
// 'jv_ID',
// 'ka_GE',
// 'kk_KZ',
// 'kl_GL',
// 'km_KH',
// 'kn_IN',
// 'ko_KR',
// 'kok_IN',
// 'lo_LA',
// 'lt_LT',
// 'lv_LV',
// 'mg_MG',
// 'mk_MK',
// 'ml_IN',
// 'mn_MN',
// 'mr_IN',
// 'ms_MY',
// 'mt_MT',
// 'my_MM',
// 'mni_IN',
// 'na_NR',
// 'nb_NO',
// 'ne_NP',
// 'nl_NL',
// 'nn_NO',
// 'no_NO',
// 'oc_FR',
// 'or_IN',
// 'pa_IN',
// 'pl_PL',
// 'ps_AF',
'pt_PT',
'pt_BR',
// 'rm_CH',
// 'rn_BI',
'ro_RO',
// 'ru_RU',
// 'sa_IN',
// 'sc_IT',
// 'sg_CF',
// 'si_LK',
// 'sk_SK',
// 'sl_SI',
// 'so_SO',
// 'sq_AL',
// 'sr_YU',
// 'sv_SE',
// 'te_IN',
// 'tg_TJ',
// 'th_TH',
// 'tk_TM',
// 'tl_PH',
// 'to_TO',
// 'tr_TR',
// 'uk_UA',
// 'ur_PK',
// 'uz_UZ',
// 'vi_VN',
// 'wa_BE',
// 'wen_DE',
// 'lp_SG',
'zh_ZH',
'yi_US',
];
$dir = $depth . '/interface/locale';
chdir( $dir );
foreach ( $locales as $locale ) {
if ( !is_dir( './' . $locale ) ) {
$cmd = "mkdir $locale && mkdir $locale/LC_MESSAGES && msginit --no-translator -l $locale -o $locale/LC_MESSAGES/messages.po -i messages.pot";
shell_exec( $cmd );
}
}
?>

View File

@ -0,0 +1,325 @@
#!/usr/bin/php
<?php
/*********************************************************************************
*
* TimeTrex is a Workforce Management program developed by
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* 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 Affero General Public License for more
* details.
*
*
* You should have received a copy of the GNU Affero General Public License along
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
*
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
*
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by TimeTrex".
*
********************************************************************************/
/*
* File Contributed By: Open Source Consulting, S.A. San Jose, Costa Rica.
* http://osc.co.cr
*/
if ( PHP_SAPI != 'cli' ) {
echo "This script can only be called from the Command Line.\n";
exit;
}
// This script will send an email notification to the translator(s) listed in any
// messages.po file. The notification basically says that the application has
// been updated and it would be great if they can review/update the translations.
// This script is intended to be run by hand. It is important that one person be in
// charge of this, as we do not want to be spamming people over and over.
$root_dir = '../../interface/locale';
if ( count( $argv ) > 1 ) {
$root_dir = $argv[1];
}
$d = opendir( $root_dir );
if ( $d ) {
$outpath = $root_dir . '/' . 'statistics.txt';
$fh = fopen( $outpath, 'w' );
$ignore_dirs = [ '.', '..', 'CVS' ];
while ( false !== ( $file = readdir( $d ) ) ) {
if ( is_dir( $root_dir . '/' . $file ) && !in_array( $file, $ignore_dirs ) ) {
$stats = calcStats( $root_dir, $file );
$pct = $stats['pct_complete'];
$team = $stats['team'];
$trans = $stats['translator'];
$string_lang = lang( $file );
$emailTeam = search_email( $team );
if ( $emailTeam != null ) {
send_mail( $emailTeam, 'timetrex', $string_lang, $pct );
}
$emailTrans = search_email( $trans );
if ( $emailTrans != null ) {
send_mail( $emailTrans, 'timetrex', $string_lang, $pct );
}
fwrite( $fh, "$file|$pct|$team|$trans|$string_lang\n" );
}
}
closedir( $d );
fclose( $fh );
}
function calcStats( $root_dir, $locale ) {
$messages = 0;
$translations = 0;
$fuzzy = 0;
$team = '';
$trans = '';
$path = $root_dir . '/' . $locale . '/LC_MESSAGES/messages.po';
// echo "<li><b>$path</b>";
if ( file_exists( $path ) ) {
$lines = file( $path );
$in_msgid = false;
$in_msgstr = false;
$found_translation = false;
$found_msg = false;
foreach ( $lines as $line ) {
// ignore comment lines
if ( $line[0] == '#' ) {
continue;
}
// Parse out the contributors.
if ( strstr( $line, '"Language-Team: ' ) ) {
$endpos = strpos( $line, '\n' );
if ( $endpos === false ) {
$endpos = strlen( $line ) - 2;
}
$len = strlen( '"Language-Team: ' );
$field = substr( $line, $len, $endpos - $len );
$names = explode( ',', $field );
foreach ( $names as $name ) {
if ( $name != 'none' ) {
if ( $team != '' ) {
$team .= ',';
}
$team .= trim( $name );
}
}
}
//Parse the Last-Translator
if ( strstr( $line, '"Last-Translator: ' ) ) {
$endpos = strpos( $line, '\n' );
if ( $endpos === false ) {
$endpos = strlen( $line ) - 2;
}
$len = strlen( '"Last-Translator: ' );
$field = substr( $line, $len, $endpos - $len );
$Transnames = explode( ',', $field );
foreach ( $Transnames as $Transname ) {
if ( $Transname != 'Automatically generated' ) {
if ( $trans != '' ) {
$trans .= ',';
}
$trans .= trim( $Transname );
}
}
}
if ( strstr( $line, 'msgid "' ) ) {
$in_msgid = true;
$in_msgstr = false;
$found_msg = false;
$found_translation = false;
}
if ( $in_msgid && !$found_msg && strstr( $line, '"' ) && !strstr( $line, '""' ) ) {
// echo "<li>msgid: $line";
$found_msg = true;
$messages++;
} else if ( strstr( $line, 'msgstr "' ) ) {
$in_msgstr = true;
$in_msgid = false;
}
if ( $in_msgstr && $found_msg && !$found_translation ) {
if ( strstr( $line, '"' ) && !strstr( $line, '""' ) ) {
// echo "<li>msgstr: $line";
$translations++;
$found_translation = true;
}
} else if ( strstr( $line, '#, fuzzy' ) ) {
$fuzzy++;
}
}
}
$translations -= $fuzzy;
$pct_complete = $messages ? (int)( ( $translations / $messages ) * 100 ) : 0;
return [ 'pct_complete' => $pct_complete, 'team' => $team, 'translator' => $trans ];
}
function statistics( $cad ) {
$names = explode( ',', $cad );
foreach ( $names as $name ) {
if ( strstr( $name, ' translated' ) ) {
$translated = $name;
} else {
if ( strstr( $name, ' fuzzy' ) ) {
$fuzzy = $name;
} else {
if ( strstr( $name, ' untranslated' ) ) {
$untranslated = $name;
}
}
}
}
return [ 'translated' => $translated, 'fuzzy' => $fuzzy, 'untranslated' => $untranslated ];
}
function send_mail( $to, $from, $lang, $pct ) {
$subject = <<<END
Timetrex updated, {$lang} translation out of date
END;
$msg = <<<END
to: {$to}
from: {$from}
subject: {$subject}
Hello,
You are receiving this email because you previously contributed {$lang}
translations to Timetrex. The application has recently been updated, which
means that new english text needs to be translated.
As of this moment, the {$lang} translation file is {$pct}% complete.
If you could find a few minutes to update the translation file, it would be
greatly appreciated. In any event, we thank-you for your previous contribution,
which has helped the site reach many {$lang} readers.
You can always find the latest language files and instructions at:
*TODO_NEED_URL_HERE*
Best,
Timetrex
END;
$msg = wordwrap( $msg, 100 );
$subject = wordwrap( $subject, 100 );
mail( $to, $subject, $msg );
}
function lang( $cad ) {
$languages = [
'af_ZA' => 'Afrikaans', 'am_ET' => 'Amharic', 'as_IN' => 'Assamese', 'az_AZ' => 'Azerbaijani',
'be_BY' => 'Belarusian', 'bg_BG' => 'Bulgarian', 'bn_IN' => 'Bengali', 'bo_CN' => 'Tibetan',
'br_FR' => 'Breton', 'bs_BA' => 'Bosnian', 'ca_ES' => 'Catalan', 'ce_RU' => 'Chechen', 'co_FR' => 'Corsican',
'cs_CZ' => 'Czech', 'cy_GB' => 'Welsh', 'da_DK' => 'Danish', 'de_DE' => 'German', 'dz_BT' => 'Dzongkha', 'el_GR' => 'Greek',
'en_US' => 'English', 'es_ES' => 'Spanish', 'et_EE' => 'Estonian', 'fa_IR' => 'Persian', 'fi_FI' => 'Finnish',
'fj_FJ' => 'Fijian', 'fo_FO' => 'Faroese', 'fr_FR' => 'French', 'ga_IE' => 'Irish', 'gd_GB' => 'Scots',
'gu_IN' => 'Gujarati', 'he_IL' => 'Hebrew', 'hi_IN' => 'Hindi', 'hr_HR' => 'Croatian', 'hu_HU' => 'Hungarian',
'hy_AM' => 'Armenian', 'id_ID' => 'Indonesian', 'is_IS' => 'Icelandic', 'it_IT' => 'Italian', 'ja_JP' => 'Japanese',
'jv_ID' => 'jv', 'ka_GE' => 'GeorgKoreanian', 'kk_KZ' => 'Kazakh', 'kl_GL' => 'Kalaallisut', 'km_KH' => 'Khmer',
'kn_IN' => 'Kannada', 'kok_IN' => 'Konkani', 'ko_KR' => 'Korean', 'lo_LA' => 'Laotian', 'lt_LT' => 'Lithuanian',
'lv_LV' => 'Latvian', 'mg_MG' => 'Malagasy', 'mk_MK' => 'Macedonian', 'ml_IN' => 'Malayalam', 'mni_IN' => 'Manipuri',
'mn_MN' => 'Mongolian', 'mr_IN' => 'Marathi', 'ms_MY' => 'Malay', 'mt_MT' => 'Maltese', 'my_MM' => 'Burmese',
'na_NR' => 'Nauru', 'nb_NO' => 'Norwegian', 'ne_NP' => 'Nepali', 'nl_NL' => 'Dutch', 'nn_NO' => 'Norwegian',
'oc_FR' => 'Occitan', 'or_IN' => 'Oriya', 'pa_IN' => 'Punjabi', 'pl_PL' => 'Polish', 'ps_AF' => 'Pashto', 'pt_PT' => 'Portuguese',
'rm_CH' => 'Rhaeto-Roman', 'rn_BI' => 'Kirundi', 'ro_RO' => 'Romanian', 'ru_RU' => 'Russian', 'sa_IN' => 'Sanskrit',
'sc_IT' => 'Sardinian', 'sg_CF' => 'Sango', 'si_LK' => 'Sinhalese', 'sk_SK' => 'Slovak', 'sl_SI' => 'Slovenian',
'so_SO' => 'Somali', 'sq_AL' => 'Albanian', 'sr_YU' => 'Serbian', 'sv_SE' => 'Swedish', 'te_IN' => 'Telugu',
'tg_TJ' => 'Tajik', 'th_TH' => 'Thai', 'tk_TM' => 'Turkmen', 'tl_PH' => 'Tagalog', 'to_TO' => 'Tonga', 'tr_TR' => 'Turkish',
'uk_UA' => 'Ukrainian', 'ur_PK' => 'Urdu', 'uz_UZ' => 'Uzbek', 'vi_VN' => 'Vietnamese', 'wa_BE' => 'wa', 'wen_DE' => 'Sorbian',
];
return ( $languages[$cad] );
}
function search_email( $cad ) {
$names = '';
$i = 0;
$name = '';
$names = explode( ' ', $cad );
foreach ( $names as $name ) {
for ( $i = 0; $i <= strlen( $name ); $i++ ) {
if ( $name[$i] == "<" || $name[$i] == ">" ) {
$name[$i] = " ";
}
}
if ( check_email_address( trim( $name ) ) ) {
return ( $name );
break;
}
}
}
function check_email_address( $email ) {
// check @
if ( !ereg( "[^@]{1,64}@[^@]{1,255}", $email ) ) {
// Email error @'s
return false;
}
$email_array = explode( "@", $email );
$local_array = explode( ".", $email_array[0] );
for ( $i = 0; $i < sizeof( $local_array ); $i++ ) {
if ( !ereg( "^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^
_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $local_array[$i] ) ) {
return false;
}
}
if ( !ereg( "^\[?[0-9\.]+\]?$", $email_array[1] ) ) {
// check domain
$domain_array = explode( ".", $email_array[1] );
if ( sizeof( $domain_array ) < 2 ) {
return false; // Domain false
}
for ( $i = 0; $i < sizeof( $domain_array ); $i++ ) {
if ( !ereg( "^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", $domain_array[$i] ) ) {
return false;
}
}
}
return true;
}
?>

179
tools/i18n/po2json.php Normal file
View File

@ -0,0 +1,179 @@
<?php
if ( PHP_SAPI != 'cli' ) {
echo "This script can only be called from the Command Line.\n";
exit;
}
/**
* String object
*/
class PoeditString {
public $key;
public $value;
public $fuzzy;
public $comments;
function __construct( $key, $value = '', $fuzzy = false, $comments = [] ) {
$this->key = $key;
$this->value = $value;
$this->fuzzy = $fuzzy;
$this->comments = (array)$comments;
}
public function __toString() {
$str = '';
foreach ( $this->comments as $c ) {
$str .= "#: $c\n";
}
if ( $this->fuzzy ) {
$str .= "#, fuzzy\n";
}
$str .= 'msgid "' . str_replace( '"', '\\"', $this->key ) . '"' . "\n";
$str .= 'msgstr "' . str_replace( '"', '\\"', $this->value ) . '"' . "\n";
$str .= "\n";
return $str;
}
}
/**
* Parser object
*/
class PoeditParser {
protected $file;
protected $header = '';
protected $strings = [];
protected function _fixQuotes( $str ) {
return stripslashes( $str );
}
public function __construct( $file ) {
$this->file = $file;
}
public function parse() {
$contents = file_get_contents( $this->file );
$parts = preg_split( '#(\r\n|\n){2}#', $contents, -1, PREG_SPLIT_NO_EMPTY );
$this->header = array_shift( $parts );
foreach ( $parts as $part ) {
// parse comments
$comments = [];
preg_match_all( '#^\\#: (.*?)$#m', $part, $matches, PREG_SET_ORDER );
foreach ( $matches as $m ) {
$comments[] = $m[1];
}
$isFuzzy = preg_match( '#^\\#, fuzzy$#im', $part ) ? true : false;
preg_match_all( '# ^ (msgid|msgstr)\ " ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)" $ #ixm', $part, $matches2, PREG_SET_ORDER );
$k = null;
if ( isset( $matches2[0][2] ) ) {
$k = $this->_fixQuotes( $matches2[0][2] );
}
$v = !empty( $matches2[1][2] ) ? $this->_fixQuotes( $matches2[1][2] ) : '';
$this->strings[$k] = new PoeditString( $k, $v, $isFuzzy, $comments );
}
}
public function merge( $strings ) {
foreach ( (array)$strings as $str ) {
if ( !in_array( $str, array_keys( $this->strings ) ) ) {
$this->strings[$str] = new PoeditString( $str );
}
}
}
public function getHeader() {
return $this->header;
}
public function getStrings() {
return $this->strings;
}
public function getJSON() {
$str = [];
foreach ( $this->strings as $s ) {
echo "String: Key: " . $s->key . " Value: " . $s->value . "\n";
if ( $s->value /*&& strlen($s->value) > 0*/ ) {
$str[$s->key] = $s->value;
} else {
//$str[$s->key] = $s->key; //Don't export strings that haven't been translated to save space.
}
}
return json_encode( $str );
}
public function toJSON( $outputFilename, $varName = 'l10n' ) {
$str = "$varName = " . $this->getJSON();
return file_put_contents( $outputFilename, $str ) !== false;
}
public function save( $filename = null ) {
$data = $this->header . "\n\n";
foreach ( $this->strings as $str ) {
$data .= $str;
}
return file_put_contents( $filename ? $filename : $this->file, $data ) !== false;
}
}
/**
*
* @param unknown_type $args
*/
function buildOptions( $args ) {
$options = [
'-o' => null,
'-i' => null,
'-n' => 'l10n',
];
$len = count( $args );
$i = 0;
while ( $i < $len ) {
if ( preg_match( '#^-[a-z]$#i', $args[$i] ) ) {
$options[$args[$i]] = isset( $args[$i + 1] ) ? trim( $args[$i + 1] ) : true;
$i += 2;
} else {
$options[] = $args[$i];
$i++;
}
}
return $options;
}
/**
* Script entry point
*
* Usage :
* =======
* php po2json -i <path/to/file.po> -o <path/to/file.json> {optional} -n <variable name (default is l10n)>
*
* This script is based on the project jsgettext : http://code.google.com/p/jsgettext/
* I've updated it slightly to meet my need
*/
$options = buildOptions( $argv );
if ( !file_exists( $options['-i'] ) || !is_readable( $options['-i'] ) ) {
die( "Invalid input file. Make sure it exists and is readable." . "\n" );
}
$poeditParser = new PoeditParser( $options['-i'] );
$poeditParser->parse();
if ( $poeditParser->toJSON( $options['-o'], $options['-n'] ) ) {
$strings = count( $poeditParser->getStrings() );
echo "Successfully exported " . $strings . " strings.\n";
} else {
echo "Cannor write to file '{$options['-o']}'.\n";
}

174
tools/i18n/translate.php Normal file
View File

@ -0,0 +1,174 @@
<?php
require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'global.inc.php' );
require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'CLI.inc.php' );
use Gettext\Loader\PoLoader;
use Gettext\Generator\PoGenerator;
/*
* This script when passed a gettext *.POT, or *.PO file will
* attempt to use a online service to translate each string
* to the specified language.
*
* This should hopefully serve as a good STARTING point for further
* human transation.
*
* This file will first create batched input files ready for translation.
* It will then load the translated files and create a messages.po file from them.
*
* Take .PO file and create small HTML batch files for translations
* php translate.php -s ../../interface/locale/fr_FR/LC_MESSAGES/messages.po ./tr_batches.html
*
* Using a web browser to translate the .html file, scroll all the way to the bottom of the file, save it from the Dev Tools.
*
* Translate HTML batch files back into .PO file
* php translate.php -t ../../interface/locale/fr_FR/LC_MESSAGES/messages.po ./tr_batches.html1 fr.po
*
*/
if ( PHP_SAPI != 'cli' ) {
echo "This script can only be called from the Command Line.\n";
exit;
}
if ( $argc < 3 || in_array( $argv[1], [ '--help', '-help', '-h', '-?' ] ) ) {
$help_output = "Usage: translate.php [OPTIONS] \n";
$help_output .= " Options:\n";
$help_output .= " -s [.POT or .PO] [OUT HTML]\n";
$help_output .= " Create a source translation file, suitable to be translated on mass.\n";
$help_output .= " -t [.POT or .PO] [IN HTML] [OUTFILE]\n";
echo $help_output;
} else {
//Handle command line arguments
$last_arg = count( $argv ) - 1;
if ( in_array( '-s', $argv ) ) {
$create_source = true;
} else {
$create_source = false;
}
if ( isset( $argv[$last_arg - 2] ) && $argv[2] != '' ) {
if ( !file_exists( $argv[2] ) || !is_readable( $argv[2] ) ) {
echo ".POT or .PO File: " . $argv[2] . " does not exists or is not readable!\n";
} else {
$source_file = $argv[2];
}
if ( $create_source == true ) {
$outfile = $argv[3];
$infile = null;
} else {
$infile = $argv[3];
$outfile = $argv[4];
}
echo "In File: $infile\n";
echo "Out File: $outfile\n";
//import from a .po file:
$po = new PoLoader();
$po_strings = $po->loadFile( $source_file );
if ( $create_source == true ) {
$batch_size = 1000;
//$batch_size = 999999;
$batch = 0;
$prev_batch = 0;
$i = 0;
$out = null;
$max = count( $po_strings->getTranslations() ) - 1;
echo "Max: $max\n";
foreach ( $po_strings->getTranslations() as $msg_obj ) {
//echo "$i. $msgid\n";
$msgid = preg_replace('/[\x00-\x1F\x7F]/', '', $msg_obj->getId() );
$msgstr = trim( $msg_obj->getTranslation() );
if ( $msgid == '#' || $msgstr != '' ) {
$i++;
if ( $i < $max ) {
continue;
}
}
if ( $i == 0 || $out == null ) {
echo "I = 0 OR Batch = 0\n";
$out = "<html>\n";
$out .= "<body><pre>\n";
}
if ( $i > 0 && ( $i % $batch_size == 0 || $i == $max ) ) {
$batch++;
echo "New Batch = $batch\n";
}
$out .= '<span class="' . htmlentities( $msgid ) . '">' . htmlentities( $msgid ) . "</span><br>\n";
//$out .= $i.': '. str_replace('<br>', '(11)', $msgid) ."<br>\n";
if ( $batch != $prev_batch ) {
echo "Writing...\n";
$out .= "</pre></body>\n";
$out .= "</html>\n";
//Write the file.
$output_file_name = str_replace( '.', '-'. $batch .'.', dirname( $outfile ) . DIRECTORY_SEPARATOR . basename( $outfile ) );
echo "Writing to: ". $output_file_name ."\n";
file_put_contents( $output_file_name, $out );
$out = null;
}
$prev_batch = $batch;
$i++;
}
} else {
//Load translated HTML files.
echo "Loading Translated File\n";
$file_contents = file_get_contents( $infile );
$file_contents = preg_replace( '/<html .*>/iu', '', $file_contents );
$file_contents = preg_replace( '/<head>.*<\/head>/iu', '', $file_contents );
$file_contents = preg_replace( '/<base.*>/iu', '', $file_contents );
$file_contents = preg_replace( '/<\/span>([\s]*)<br>/iu', '</span>', $file_contents );
$file_contents = preg_replace( '/<\/span><br>([\s]*)/iu', '</span>', $file_contents );
$file_contents = preg_replace( '/<font style="(.*)">/iu', '', $file_contents );
$file_contents = preg_replace( '/ :/iu', ':', $file_contents );
$file_contents = str_replace( [ '<html>', '</html>', '<body>', '</body>', '<pre>', '</pre>', '</font>' ], '', $file_contents );
$lines = explode( '</span>', $file_contents );
//var_dump($lines);
if ( is_array( $lines ) ) {
echo "Total Lines: " . count( $lines ) . "\n";
$i = 0;
foreach ( $lines as $line ) {
//Parse the string number
if ( preg_match( '/<span class=\"(.*)\">(.*)/i', trim( $line ), $matches ) == true ) {
if ( is_array( $matches ) && isset( $matches[1] ) && isset( $matches[2] ) ) {
$msgid = html_entity_decode( $matches[1] );
$msgstr = preg_replace( '/\s\"\s/iu', '"', html_entity_decode( $matches[2] ) );
echo $i . ". Translating: " . $msgid . "\n";
echo " To: " . $msgstr . "\n";
$tmp_translation = $po_strings->find( null, $msgid );
if ( $tmp_translation ) {
$tmp_translation->translate( $msgstr );
} else {
echo "Failed to find translation key...\n";
}
} else {
echo "ERROR parsing line!\n";
}
} else {
echo "Failed to match line!\n";
}
$i++;
}
}
$po_generator = new PoGenerator();
$po_generator->generateFile( $po_strings, $outfile );
}
}
}
?>

128
tools/i18n/tsmarty2c.php Normal file
View File

@ -0,0 +1,128 @@
#!/usr/bin/env php
<?php
/**
* tsmarty2c.php - rips gettext strings from smarty template
*
* ------------------------------------------------------------------------- *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
* ------------------------------------------------------------------------- *
*
* This command line script rips gettext strings from smarty file,
* and prints them to stdout in C format, that can later be used with the
* standard gettext tools.
*
* Usage:
* ./tsmarty2c.php <filename or directory> <file2> <..> > smarty.c
*
* If a parameter is a directory, the template files within will be parsed.
*
* @package smarty-gettext
* @version $Id$
* @link http://smarty-gettext.sf.net/
* @author Sagi Bashari <sagi@boom.org.il>
* @copyright 2004-2005 Sagi Bashari
*/
if ( PHP_SAPI != 'cli' ) {
echo "This script can only be called from the Command Line.\n";
exit;
}
// smarty open tag
$ldq = preg_quote( '{' );
// smarty close tag
$rdq = preg_quote( '}' );
// smarty command
$cmd = preg_quote( 't' );
// extensions of smarty files, used when going through a directory
$extensions = [ 'tpl' ];
// "fix" string - strip slashes, escape and convert new lines to \n
function fs( $str ) {
$str = stripslashes( $str );
$str = str_replace( '"', '\"', $str );
$str = str_replace( "\n", '\n', $str );
return $str;
}
// rips gettext strings from $file and prints them in C format
function do_file( $file ) {
$content = @file_get_contents( $file );
if ( empty( $content ) ) {
return;
}
global $ldq, $rdq, $cmd;
preg_match_all(
"/{$ldq}\s*({$cmd})\s*([^{$rdq}]*){$rdq}([^{$ldq}]*){$ldq}\/\\1{$rdq}/",
$content,
$matches
);
for ( $i = 0; $i < count( $matches[0] ); $i++ ) {
// TODO: add line number
echo "/* $file */\n"; // credit: Mike van Lammeren 2005-02-14
if ( preg_match( '/plural\s*=\s*["\']?\s*(.[^\"\']*)\s*["\']?/', $matches[2][$i], $match ) ) {
echo 'ngettext("' . fs( $matches[3][$i] ) . '","' . fs( $match[1] ) . '",x);' . "\n";
} else {
echo 'gettext("' . fs( $matches[3][$i] ) . '");' . "\n";
}
echo "\n";
}
}
// go through a directory
function do_dir( $dir ) {
$d = dir( $dir );
while ( false !== ( $entry = $d->read() ) ) {
if ( $entry == '.' || $entry == '..' ) {
continue;
}
$entry = $dir . '/' . $entry;
if ( is_dir( $entry ) ) { // if a directory, go through it
do_dir( $entry );
} else { // if file, parse only if extension is matched
$pi = pathinfo( $entry );
if ( isset( $pi['extension'] ) && in_array( $pi['extension'], $GLOBALS['extensions'] ) ) {
do_file( $entry );
}
}
}
$d->close();
}
for ( $ac = 1; $ac < $_SERVER['argc']; $ac++ ) {
if ( is_dir( $_SERVER['argv'][$ac] ) ) { // go through directory
do_dir( $_SERVER['argv'][$ac] );
} else { // do file
do_file( $_SERVER['argv'][$ac] );
}
}
?>

33
tools/i18n/updatetranslation.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
##$License$##
##
# File Contributed By: Open Source Consulting, S.A. San Jose, Costa Rica.
# http://osc.co.cr
##
# this script is intended to aid with accepting incoming translations (from translators)
# in a messages.po file and merging that file into an existing messages.po.
# It then merges in any changes in the master .pot file and compiles a
# .mo binary file.
# Usage:
# ./updatestranslation.sh <locale> <path_to_po_file_from_translator>
# Example:
# cd tools/i18n/
# ./updatestranslation.sh es_ES /tmp/messages.po.es_ES
# This script is intended to be run from the tools/i18n directory.
LOCALE=$1
NEW_MESSAGES=$2
dir=`pwd`
cd ../../interface/locale/$LOCALE/LC_MESSAGES/
msgmerge $NEW_MESSAGES messages.po > messages.po.new
echo `pwd`
mv messages.po.new messages.po
cd $dir
./mergelocale.sh $LOCALE