Language\ namespace update
Update the Core Language classes to have all method parameter type declaration. GetTextReader has gettext as alias to translate. GetTextReader public methods to get cache enable status and short circuit (no translation loaded) status Main language: Add new methods for plural and plural in context (__n, __p, __pn) Deprecate gettext, ngettext, _e Add new translation loader in gettext standard <locale>/LC_MESSAGES/<domain> style Including locales checker, auto detect on enviroment variables, return self as class (for functions type) return translator class after loading, etc New LoadFunctions to run all like functions. Names like php but with two underscores prefixed. eg gettext -> __gettext
This commit is contained in:
@@ -3,21 +3,22 @@
|
||||
# CREATED: 2005/08/09
|
||||
# SHORT DESCRIPTION:
|
||||
# Backned English Messages file for gettext
|
||||
# to craete: msgfmt -o ja.mo messages_en.po
|
||||
# HISTORY:
|
||||
# to craete: msgfmt -o <output.po> <input.mo>
|
||||
# ********************************************************************/
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Project Version\n"
|
||||
"Project-Id-Version: en_US.UTF-8 LC_MESSAGES admin\n"
|
||||
"Report-Msgid-Bugs-To: clemens.schwaighofer@egplusww.com\n"
|
||||
"POT-Creation-Date: 2018-03-28 10:40+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: \n"
|
||||
"Last-Translator: clemens.schwaighofer@egplusww.co\n"
|
||||
"Language-Team: E-GRAPHICS COMMUNICATIONS Japan <info.jp@egplusww.com>\n"
|
||||
"Language: en_US\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "Year"
|
||||
msgstr "Year"
|
||||
@@ -28,6 +29,24 @@ msgstr "Month"
|
||||
msgid "INPUT TEST"
|
||||
msgstr "OUTPUT TEST ADMIN EN"
|
||||
|
||||
# testing multi
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi Admin en_US 0"
|
||||
msgstr[1] "Multi Admin en_US 1"
|
||||
msgstr[2] "Multi Admin en_US 2"
|
||||
|
||||
msgctxt "month name"
|
||||
msgid "May"
|
||||
msgstr "May Admin en_US"
|
||||
|
||||
msgctxt "month name"
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi Admin month en_US 0"
|
||||
msgstr[1] "Multi Admin month en_US 1"
|
||||
msgstr[2] "Multi Admin month en_US 2"
|
||||
|
||||
msgid "I should be translated"
|
||||
msgstr "I should be translated: I WAS TRANSLATED"
|
||||
|
||||
|
||||
@@ -1,2 +1,24 @@
|
||||
# to craete: msgfmt -o <output.po> <input.mo>
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: en_US.UTF-8 LC_MESSAGES frontend\n"
|
||||
"Report-Msgid-Bugs-To: clemens.schwaighofer@egplusww.com\n"
|
||||
"POT-Creation-Date: 2018-03-28 10:40+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: clemens.schwaighofer@egplusww.co\n"
|
||||
"Language-Team: E-GRAPHICS COMMUNICATIONS Japan <info.jp@egplusww.com>\n"
|
||||
"Language: en_US\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "INPUT TEST"
|
||||
msgstr "OUTPUT TEST FRONTEND EN"
|
||||
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi frontend en_US 0"
|
||||
msgstr[1] "Multi frontend en_US 1"
|
||||
msgstr[2] "Multi frontend en_US 2"
|
||||
|
||||
@@ -3,21 +3,22 @@
|
||||
# CREATED: 2018/03/28
|
||||
# SHORT DESCRIPTION:
|
||||
# Backend Japanese Messages file for gettext
|
||||
# to craete: msgfmt -o ja.mo messages_ja.po
|
||||
# HISTORY:
|
||||
# to craete: msgfmt -o <output.po> <input.mo>
|
||||
# ********************************************************************/
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Project Version\n"
|
||||
"Project-Id-Version: ja_JP.UTF-8 LC_MESSAGES admin\n"
|
||||
"Report-Msgid-Bugs-To: clemens.schwaighofer@egplusww.com\n"
|
||||
"POT-Creation-Date: 2018-03-28 10:40+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: \n"
|
||||
"Last-Translator: clemens.schwaighofer@egplusww.com\n"
|
||||
"Language-Team: E-GRAPHICS COMMUNICATIONS Japan <info.jp@egplusww.com>\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
|
||||
msgid "Yes"
|
||||
msgstr "はい"
|
||||
@@ -65,6 +66,13 @@ msgstr "日"
|
||||
msgid "INPUT TEST"
|
||||
msgstr "OUTPUT TEST ADMIN JA"
|
||||
|
||||
# testing multi
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi Admin ja_JP 0"
|
||||
msgstr[1] "Multi Admin ja_JP 1"
|
||||
msgstr[2] "Multi Admin ja_JP 2"
|
||||
|
||||
# login string
|
||||
msgid "Hello %s"
|
||||
msgstr "こにちは %s"
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
# to craete: msgfmt -o <output.po> <input.mo>
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgid "INPUT TEST"
|
||||
msgstr "OUTPUT TEST FRONTEND JA"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
13
4dev/tests/includes/create_po.sh
Executable file
13
4dev/tests/includes/create_po.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# if we don't have one base file we are in the wrong folder
|
||||
if [ ! -f "locale/en_US/LC_MESSAGES/admin.mo" ]; then
|
||||
echo "Locale file is missing, wrong base folder?"
|
||||
echo "Should be: 4dev/tests/includes/"
|
||||
exit;
|
||||
fi;
|
||||
|
||||
msgfmt -o locale/en_US/LC_MESSAGES/admin.mo locale/en_US.admin.UTF-8.po
|
||||
msgfmt -o locale/en_US/LC_MESSAGES/frontend.mo locale/en_US.frontend.UTF-8.po
|
||||
msgfmt -o locale/ja_JP/LC_MESSAGES/admin.mo locale/ja_JP.admin.UTF-8.po
|
||||
msgfmt -o locale/ja_JP/LC_MESSAGES/frontend.mo locale/ja_JP.frontend.UTF-8.po
|
||||
@@ -1,2 +1,34 @@
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: en_US.UTF-8 LC_MESSAGES admin\n"
|
||||
"Report-Msgid-Bugs-To: clemens.schwaighofer@egplusww.com\n"
|
||||
"POT-Creation-Date: 2018-03-28 10:40+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: clemens.schwaighofer@egplusww.co\n"
|
||||
"Language-Team: E-GRAPHICS COMMUNICATIONS Japan <info.jp@egplusww.com>\n"
|
||||
"Language: en_US\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "Original"
|
||||
msgstr "Translated admin en_US"
|
||||
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi admin en_US 0"
|
||||
msgstr[1] "Multi admin en_US 1"
|
||||
msgstr[2] "Multi admin en_US 2"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "Original"
|
||||
msgstr "Original context admin en_US"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi context admin en_US 0"
|
||||
msgstr[1] "Multi context admin en_US 1"
|
||||
msgstr[2] "Multi context admin en_US 2"
|
||||
|
||||
@@ -1,2 +1,34 @@
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: en_US.UTF-8 LC_MESSAGES frontend\n"
|
||||
"Report-Msgid-Bugs-To: clemens.schwaighofer@egplusww.com\n"
|
||||
"POT-Creation-Date: 2018-03-28 10:40+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: clemens.schwaighofer@egplusww.co\n"
|
||||
"Language-Team: E-GRAPHICS COMMUNICATIONS Japan <info.jp@egplusww.com>\n"
|
||||
"Language: en_US\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "Original"
|
||||
msgstr "Translated frontend en_US"
|
||||
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi frontend en_US 0"
|
||||
msgstr[1] "Multi frontend en_US 1"
|
||||
msgstr[2] "Multi frontend en_US 2"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "Original"
|
||||
msgstr "Original context frontend en_US"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi context frontend en_US 0"
|
||||
msgstr[1] "Multi context frontend en_US 1"
|
||||
msgstr[2] "Multi context frontend en_US 2"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,2 +1,35 @@
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: ja_JP.UTF-8 LC_MESSAGES admin\n"
|
||||
"Report-Msgid-Bugs-To: clemens.schwaighofer@egplusww.com\n"
|
||||
"POT-Creation-Date: 2018-03-28 10:40+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: clemens.schwaighofer@egplusww.co\n"
|
||||
"Language-Team: E-GRAPHICS COMMUNICATIONS Japan <info.jp@egplusww.com>\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
|
||||
# 0, 1, 2 plural
|
||||
|
||||
msgid "Original"
|
||||
msgstr "Translated admin ja_JP"
|
||||
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi admin ja_JP 0"
|
||||
msgstr[1] "Multi admin ja_JP 1"
|
||||
msgstr[2] "Multi admin ja_JP 2"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "Original"
|
||||
msgstr "Original context admin ja_JP"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi context admin ja_JP 0"
|
||||
msgstr[1] "Multi context admin ja_JP 1"
|
||||
msgstr[2] "Multi context admin ja_JP 2"
|
||||
|
||||
@@ -1,2 +1,35 @@
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: ja_JP.UTF-8 LC_MESSAGES frontend\n"
|
||||
"Report-Msgid-Bugs-To: clemens.schwaighofer@egplusww.com\n"
|
||||
"POT-Creation-Date: 2018-03-28 10:40+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: clemens.schwaighofer@egplusww.co\n"
|
||||
"Language-Team: E-GRAPHICS COMMUNICATIONS Japan <info.jp@egplusww.com>\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
|
||||
# 0, 1, 2 plural
|
||||
|
||||
msgid "Original"
|
||||
msgstr "Translated frontend ja_JP"
|
||||
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi frontend ja_JP 0"
|
||||
msgstr[1] "Multi frontend ja_JP 1"
|
||||
msgstr[2] "Multi frontend ja_JP 2"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "Original"
|
||||
msgstr "Original context frontend ja_JP"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "single"
|
||||
msgid_plural "multi"
|
||||
msgstr[0] "Multi context frontend ja_JP 0"
|
||||
msgstr[1] "Multi context frontend ja_JP 1"
|
||||
msgstr[2] "Multi context frontend ja_JP 2"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -40,15 +40,35 @@ use CoreLibs\Language\L10n;
|
||||
|
||||
$string = 'INPUT TEST';
|
||||
|
||||
echo "<br><b>LEGACY TEST</b><br>";
|
||||
|
||||
$lang = 'en_utf8';
|
||||
$l = new CoreLibs\Language\L10n($lang);
|
||||
echo "*<br>";
|
||||
echo "LANGUAGE WANT/SET: " . $lang . '/' . $l->getLocale() . "<br>";
|
||||
echo "LANGUAGE FILE: " . $l->getMoFile() . "<br>";
|
||||
echo "LOAD ERROR: " . $l->getLoadError() . "<br>";
|
||||
echo "INPUT TEST: " . $string . " => " . $l->__($string) . "<br>";
|
||||
$single_string = 'single';
|
||||
$multi_string = 'multi';
|
||||
for ($n = 0; $n <= 3; $n++) {
|
||||
echo "MULTI TEST $n: " . $single_string . "/" . $multi_string . " => "
|
||||
. $l->__n($single_string, $multi_string, $n) . "<br>";
|
||||
}
|
||||
$context = "month name";
|
||||
$context_string = "May";
|
||||
echo "CONTEXT TRANSLATION: " . $context_string . " => " . $l->__p($context, $context_string) . "<br>";
|
||||
$single_string = 'single';
|
||||
$multi_string = 'multi';
|
||||
for ($n = 0; $n <= 3; $n++) {
|
||||
echo "CONTEXT MULTI TEST $n: " . $single_string . "/" . $multi_string . " => "
|
||||
. $l->__pn($context, $single_string, $multi_string, $n) . "<br>";
|
||||
}
|
||||
|
||||
// switch to other language
|
||||
$lang = 'ja_utf8';
|
||||
$l->l10nReloadMOfile($lang);
|
||||
echo "*<br>";
|
||||
echo "LANGUAGE WANT/SET: " . $lang . '/' . $l->getLocale() . "<br>";
|
||||
echo "LANGUAGE FILE: " . $l->getMoFile() . "<br>";
|
||||
echo "LOAD ERROR: " . $l->getLoadError() . "<br>";
|
||||
@@ -56,6 +76,7 @@ echo "INPUT TEST: " . $string . " => " . $l->__($string) . "<br>";
|
||||
// switch to non existing language
|
||||
$lang = 'tr_utf8';
|
||||
$l->l10nReloadMOfile($lang);
|
||||
echo "*<br>";
|
||||
echo "LANGUAGE WANT/SET: " . $lang . '/' . $l->getLocale() . "<br>";
|
||||
echo "LANGUAGE FILE: " . $l->getMoFile() . "<br>";
|
||||
echo "LOAD ERROR: " . $l->getLoadError() . "<br>";
|
||||
@@ -79,33 +100,64 @@ $encoding = 'UTF-8';
|
||||
$path = BASE . INCLUDES . LOCALE;
|
||||
$l = new CoreLibs\Language\L10n($lang, $path, $domain, false);
|
||||
|
||||
echo "*<br>";
|
||||
echo "LANGUAGE WANT/SET: " . $lang . '/' . $l->getLocale() . "<br>";
|
||||
echo "DOMAIN WANT/SET: " . $domain . '/' . $l->getDomain() . "<br>";
|
||||
echo "LANGUAGE FILE: " . $l->getMoFile() . "<br>";
|
||||
echo "CONTENT PATH: " . $l->getBaseContentPath() . "<br>";
|
||||
echo "DOMAIN PATH: " . $l->getTextDomain($domain) . "<br>";
|
||||
echo "BASE PATH: " . $l->getBaseLocalePath() . "<br>";
|
||||
echo "LOAD ERROR: " . $l->getLoadError() . "<br>";
|
||||
echo "INPUT TEST: " . $string . " => " . $l->__($string) . "<br>";
|
||||
echo "TROUGH LOAD: " . $l->getTranslatorClass()->gettext($string) . "<br>";
|
||||
$single_string = 'single';
|
||||
$multi_string = 'multi';
|
||||
for ($n = 0; $n <= 3; $n++) {
|
||||
echo "MULTI TEST $n: " . $single_string . "/" . $multi_string . " => "
|
||||
. $l->__n($single_string, $multi_string, $n) . "<br>";
|
||||
}
|
||||
|
||||
$domain = 'frontend';
|
||||
$l->getTranslator('', $path, $domain);
|
||||
echo "*<br>";
|
||||
echo "LANGUAGE WANT/SET: " . $lang . '/' . $l->getLocale() . "<br>";
|
||||
echo "DOMAIN WANT/SET: " . $domain . '/' . $l->getDomain() . "<br>";
|
||||
echo "LANGUAGE FILE: " . $l->getMoFile() . "<br>";
|
||||
echo "CONTENT PATH: " . $l->getBaseContentPath() . "<br>";
|
||||
echo "DOMAIN PATH: " . $l->getTextDomain($domain) . "<br>";
|
||||
echo "BASE PATH: " . $l->getBaseLocalePath() . "<br>";
|
||||
echo "LOAD ERROR: " . $l->getLoadError() . "<br>";
|
||||
echo "INPUT TEST: " . $string . " => " . $l->__($string) . "<br>";
|
||||
echo "TROUGH LOAD: " . $l->getTranslatorClass()->gettext($string) . "<br>";
|
||||
|
||||
|
||||
echo "<br><b>STATIC TYPE</b><br>";
|
||||
$domain = 'admin';
|
||||
echo "<br><b>STATIC TYPE TEST</b><br>";
|
||||
// static tests from l10n_load
|
||||
L10n::getInstance()->setLocale($lang);
|
||||
echo "SET LOCALE: " . L10n::getInstance()->getLocale() . "<br>";
|
||||
L10n::getInstance()->setDomain($domain);
|
||||
echo "SET DOMAIN: " . L10n::getInstance()->getDomain() . "<br>";
|
||||
L10n::getInstance()->setTextDomain($domain, $path);
|
||||
echo "SET DOMAIN: " . L10n::getInstance()->getTextDomain($domain) . "<br>";
|
||||
echo "SET TEXT DOMAIN: " . L10n::getInstance()->getTextDomain($domain) . "<br>";
|
||||
// null call __bind_textdomain_codeset
|
||||
echo "INPUT TEST: " . $string . " => " . L10n::getInstance()->getTranslator()->gettext($string) . "<br>";
|
||||
|
||||
echo "<br><b>FUNCTIONS</b><br>";
|
||||
// real statisc test
|
||||
L10n::loadFunctions();
|
||||
__setlocale(LC_MESSAGES, $lang);
|
||||
$locale = 'ja';
|
||||
__setlocale(LC_MESSAGES, $locale);
|
||||
__textdomain($domain);
|
||||
__bindtextdomain($domain, $path);
|
||||
__bind_textdomain_codeset($domain, $encoding);
|
||||
echo "INPUT TEST: " . $string . " => " . __($string) . "<br>";
|
||||
echo "INPUT TEST $locale: " . $string . " => " . __($string) . "<br>";
|
||||
|
||||
$locale = 'en_US.UTF-8';
|
||||
__setlocale(LC_MESSAGES, $locale);
|
||||
__textdomain($domain);
|
||||
__bindtextdomain($domain, $path);
|
||||
__bind_textdomain_codeset($domain, $encoding);
|
||||
echo "INPUT TEST $locale: " . $string . " => " . __($string) . "<br>";
|
||||
|
||||
print "</body></html>";
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -715,20 +715,20 @@ class Basic
|
||||
|
||||
// *** ARRAY HANDLING END
|
||||
// [!!! DEPRECATED !!!]
|
||||
// Moved to \CoreLibs\Language\Encoding
|
||||
// Moved to \CoreLibs\Convert\MimeEncode
|
||||
|
||||
/**
|
||||
* wrapper function for mb mime convert, for correct conversion with long strings
|
||||
* @param string $string string to encode
|
||||
* @param string $encoding target encoding
|
||||
* @return string encoded string
|
||||
* @deprecated Use \CoreLibs\Language\Encoding::__mbMimeEncode() instead
|
||||
* @deprecated Use \CoreLibs\Convert\MimeEncode::__mbMimeEncode() instead
|
||||
*/
|
||||
public static function __mbMimeEncode(string $string, string $encoding): string
|
||||
{
|
||||
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Language\Encoding::__mbMimeEncode()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Language\Encoding::__mbMimeEncode($string, $encoding);
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Convert\MimeEncode::__mbMimeEncode()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Convert\MimeEncode::__mbMimeEncode($string, $encoding);
|
||||
}
|
||||
|
||||
// *** HUMAND BYTE READABLE CONVERT
|
||||
@@ -1009,7 +1009,7 @@ class Basic
|
||||
|
||||
// *** ENCODING FUNCTIONS
|
||||
// [!!! DEPRECATED !!!]
|
||||
// Moved to \CoreLibs\Language\Encoding
|
||||
// Moved to \CoreLibs\Check\Encoding and \CoreLibs\Convert\Encoding
|
||||
|
||||
/**
|
||||
* test if a string can be safely convert between encodings. mostly utf8 to shift jis
|
||||
@@ -1026,12 +1026,12 @@ class Basic
|
||||
* @param string $from_encoding encoding of string to test
|
||||
* @param string $to_encoding target encoding
|
||||
* @return bool|array<mixed> false if no error or array with failed characters
|
||||
* @deprecated use \CoreLibs\Language\Encoding::checkConvertEncoding() instead
|
||||
* @deprecated use \CoreLibs\Check\Encoding::checkConvertEncoding() instead
|
||||
*/
|
||||
public function checkConvertEncoding(string $string, string $from_encoding, string $to_encoding)
|
||||
{
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Language\Encoding::checkConvertEncoding()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Language\Encoding::checkConvertEncoding($string, $from_encoding, $to_encoding);
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Encoding::checkConvertEncoding()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Check\Encoding::checkConvertEncoding($string, $from_encoding, $to_encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1047,12 +1047,12 @@ class Basic
|
||||
* check that the source is actually matching
|
||||
* to what we sav the source is
|
||||
* @return string encoding converted string
|
||||
* @deprecated use \CoreLibs\Language\Encoding::convertEncoding() instead
|
||||
* @deprecated use \CoreLibs\Convert\Encoding::convertEncoding() instead
|
||||
*/
|
||||
public static function convertEncoding(string $string, string $to_encoding, string $source_encoding = '', bool $auto_check = true): string
|
||||
{
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Language\Encoding::convertEncoding()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Language\Encoding::convertEncoding($string, $to_encoding, $source_encoding, $auto_check);
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Convert\Encoding::convertEncoding()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Convert\Encoding::convertEncoding($string, $to_encoding, $source_encoding, $auto_check);
|
||||
}
|
||||
|
||||
// *** ENCODING FUNCTIONS END
|
||||
|
||||
@@ -39,7 +39,7 @@ class FileReader
|
||||
* file read constructor
|
||||
* @param string $filename file name to load
|
||||
*/
|
||||
public function __construct($filename)
|
||||
public function __construct(string $filename)
|
||||
{
|
||||
if (file_exists($filename)) {
|
||||
$this->fr_length = filesize($filename) ?: 0;
|
||||
@@ -58,7 +58,7 @@ class FileReader
|
||||
* @param int $bytes how many bytes to read
|
||||
* @return string read data as string
|
||||
*/
|
||||
public function read($bytes)
|
||||
public function read(int $bytes): string
|
||||
{
|
||||
if (!$bytes || !is_resource($this->fr_fd)) {
|
||||
return '';
|
||||
@@ -86,7 +86,7 @@ class FileReader
|
||||
* @param int $pos position where to go to
|
||||
* @return int file position after seek done
|
||||
*/
|
||||
public function seekto($pos)
|
||||
public function seekto(int $pos): int
|
||||
{
|
||||
if (!is_resource($this->fr_fd)) {
|
||||
return 0;
|
||||
@@ -100,7 +100,7 @@ class FileReader
|
||||
* get current position in file
|
||||
* @return int current position in bytes
|
||||
*/
|
||||
public function currentpos()
|
||||
public function currentpos(): int
|
||||
{
|
||||
return $this->fr_pos;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ class FileReader
|
||||
* file length/size
|
||||
* @return int file size in bytes
|
||||
*/
|
||||
public function length()
|
||||
public function length(): int
|
||||
{
|
||||
return $this->fr_length;
|
||||
}
|
||||
|
||||
@@ -67,17 +67,15 @@ class GetTextReader
|
||||
/** @var array<mixed> */
|
||||
private $cache_translations = []; // original -> translation mapping
|
||||
|
||||
|
||||
/* Methods */
|
||||
|
||||
|
||||
/**
|
||||
* Reads a 32bit Integer from the Stream
|
||||
*
|
||||
* @access private
|
||||
* @return int Integer from the Stream
|
||||
*/
|
||||
private function readint()
|
||||
private function readint(): int
|
||||
{
|
||||
if ($this->BYTEORDER == 0) {
|
||||
// low endian
|
||||
@@ -91,10 +89,11 @@ class GetTextReader
|
||||
|
||||
/**
|
||||
* read bytes
|
||||
*
|
||||
* @param int $bytes byte length to read
|
||||
* @return string return data, possible string
|
||||
*/
|
||||
public function read($bytes)
|
||||
public function read(int $bytes): string
|
||||
{
|
||||
return $this->STREAM->read($bytes);
|
||||
}
|
||||
@@ -105,7 +104,7 @@ class GetTextReader
|
||||
* @param int $count How many elements should be read
|
||||
* @return array<mixed> Array of Integers
|
||||
*/
|
||||
public function readintarray($count)
|
||||
public function readintarray(int $count): array
|
||||
{
|
||||
if ($this->BYTEORDER == 0) {
|
||||
// low endian
|
||||
@@ -120,9 +119,10 @@ class GetTextReader
|
||||
* Constructor
|
||||
*
|
||||
* @param FileReader|bool $Reader the StreamReader object
|
||||
* @param bool $enable_cache Enable or disable caching of strings (default on)
|
||||
* @param bool $enable_cache Enable or disable caching
|
||||
* of strings (default on)
|
||||
*/
|
||||
public function __construct($Reader, $enable_cache = true)
|
||||
public function __construct($Reader, bool $enable_cache = true)
|
||||
{
|
||||
// If there isn't a StreamReader, turn on short circuit mode.
|
||||
if ((!is_object($Reader) && !$Reader) || (is_object($Reader) && $Reader->error)) {
|
||||
@@ -159,6 +159,26 @@ class GetTextReader
|
||||
$this->translations = $this->readint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current short circuit, equals to no translator running
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getShortCircuit(): bool
|
||||
{
|
||||
return $this->short_circuit;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current cache enabled status
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getEnableCache(): bool
|
||||
{
|
||||
return $this->enable_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the translation tables from the MO file into the cache
|
||||
* If caching is enabled, also loads all strings into a cache
|
||||
@@ -207,7 +227,7 @@ class GetTextReader
|
||||
* @param int $num Offset number of original string
|
||||
* @return string Requested string if found, otherwise ''
|
||||
*/
|
||||
private function getOriginalString($num)
|
||||
private function getOriginalString(int $num): string
|
||||
{
|
||||
$length = $this->table_originals[$num * 2 + 1] ?? 0;
|
||||
$offset = $this->table_originals[$num * 2 + 2] ?? 0;
|
||||
@@ -226,7 +246,7 @@ class GetTextReader
|
||||
* @param int $num Offset number of original string
|
||||
* @return string Requested string if found, otherwise ''
|
||||
*/
|
||||
private function getTranslationString($num)
|
||||
private function getTranslationString(int $num): string
|
||||
{
|
||||
$length = $this->table_translations[$num * 2 + 1] ?? 0;
|
||||
$offset = $this->table_translations[$num * 2 + 2] ?? 0;
|
||||
@@ -242,12 +262,12 @@ class GetTextReader
|
||||
* Binary search for string
|
||||
*
|
||||
* @access private
|
||||
* @param string $string string to find
|
||||
* @param int $start (internally used in recursive function)
|
||||
* @param int $end (internally used in recursive function)
|
||||
* @return int (offset in originals table)
|
||||
* @param string $string string to find
|
||||
* @param int $start (internally used in recursive function)
|
||||
* @param int $end (internally used in recursive function)
|
||||
* @return int (offset in originals table)
|
||||
*/
|
||||
private function findString($string, $start = -1, $end = -1)
|
||||
private function findString(string $string, int $start = -1, int $end = -1): int
|
||||
{
|
||||
if (($start == -1) or ($end == -1)) {
|
||||
// findString is called with only one parameter, set start end end
|
||||
@@ -289,7 +309,7 @@ class GetTextReader
|
||||
* @param string $string to be translated
|
||||
* @return string translated string (or original, if not found)
|
||||
*/
|
||||
public function translate($string)
|
||||
public function translate(string $string): string
|
||||
{
|
||||
if ($this->short_circuit) {
|
||||
return $string;
|
||||
@@ -298,7 +318,10 @@ class GetTextReader
|
||||
|
||||
if ($this->enable_cache) {
|
||||
// Caching enabled, get translated string from cache
|
||||
if (is_array($this->cache_translations) && array_key_exists($string, $this->cache_translations)) {
|
||||
if (
|
||||
is_array($this->cache_translations) &&
|
||||
array_key_exists($string, $this->cache_translations)
|
||||
) {
|
||||
return $this->cache_translations[$string];
|
||||
} else {
|
||||
return $string;
|
||||
@@ -321,7 +344,7 @@ class GetTextReader
|
||||
* @param string $expr an expression to match
|
||||
* @return string sanitized plural form expression
|
||||
*/
|
||||
private function sanitizePluralExpression($expr)
|
||||
private function sanitizePluralExpression(string $expr): string
|
||||
{
|
||||
// Get rid of disallowed characters.
|
||||
$expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
|
||||
@@ -358,7 +381,7 @@ class GetTextReader
|
||||
* @param string $header header search in plurals
|
||||
* @return string verbatim plural form header field
|
||||
*/
|
||||
private function extractPluralFormsHeaderFromPoHeader($header)
|
||||
private function extractPluralFormsHeaderFromPoHeader(string $header): string
|
||||
{
|
||||
if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) {
|
||||
$expr = $regs[2];
|
||||
@@ -374,14 +397,14 @@ class GetTextReader
|
||||
* @access private
|
||||
* @return string plural form header
|
||||
*/
|
||||
private function getPluralForms()
|
||||
private function getPluralForms(): string
|
||||
{
|
||||
// lets assume message number 0 is header
|
||||
// this is true, right?
|
||||
$this->loadTables();
|
||||
|
||||
// cache header field for plural forms
|
||||
if (! is_string($this->pluralheader)) {
|
||||
if (empty($this->pluralheader) || !is_string($this->pluralheader)) {
|
||||
if ($this->enable_cache) {
|
||||
$header = $this->cache_translations[''];
|
||||
} else {
|
||||
@@ -397,25 +420,37 @@ class GetTextReader
|
||||
* Detects which plural form to take
|
||||
*
|
||||
* @access private
|
||||
* @param string $n count
|
||||
* @return int array index of the right plural form
|
||||
* @param int $n count
|
||||
* @return int array index of the right plural form
|
||||
*/
|
||||
private function selectString($n)
|
||||
private function selectString(int $n): int
|
||||
{
|
||||
$string = $this->getPluralForms();
|
||||
$string = str_replace('nplurals', "\$total", $string);
|
||||
$string = str_replace("n", $n, $string);
|
||||
$string = str_replace("n", (string)$n, $string);
|
||||
$string = str_replace('plural', "\$plural", $string);
|
||||
|
||||
$total = 0;
|
||||
$plural = 0;
|
||||
|
||||
eval("$string");
|
||||
/** @phpstan-ignore-next-line */
|
||||
/** @phpstan-ignore-next-line 0 >= 0 is always true*/
|
||||
if ($plural >= $total) {
|
||||
$plural = $total - 1;
|
||||
}
|
||||
return $plural;
|
||||
return (int)$plural;
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper for translate() method
|
||||
*
|
||||
* @access public
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public function gettext(string $string): string
|
||||
{
|
||||
return $this->translate($string);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,10 +459,10 @@ class GetTextReader
|
||||
* @access public
|
||||
* @param string $single
|
||||
* @param string $plural
|
||||
* @param string $number
|
||||
* @param int $number
|
||||
* @return string plural form
|
||||
*/
|
||||
public function ngettext($single, $plural, $number)
|
||||
public function ngettext(string $single, string $plural, int $number): string
|
||||
{
|
||||
if ($this->short_circuit) {
|
||||
if ($number != 1) {
|
||||
@@ -465,11 +500,12 @@ class GetTextReader
|
||||
|
||||
/**
|
||||
* p get text
|
||||
*
|
||||
* @param string $context [description]
|
||||
* @param string $msgid [description]
|
||||
* @return string [description]
|
||||
*/
|
||||
public function pgettext($context, $msgid)
|
||||
public function pgettext(string $context, string $msgid): string
|
||||
{
|
||||
$key = $context . chr(4) . $msgid;
|
||||
$ret = $this->translate($key);
|
||||
@@ -482,14 +518,19 @@ class GetTextReader
|
||||
|
||||
/**
|
||||
* np get text
|
||||
*
|
||||
* @param string $context [description]
|
||||
* @param string $singular [description]
|
||||
* @param string $plural [description]
|
||||
* @param string $number [description]
|
||||
* @param int $number [description]
|
||||
* @return string [description]
|
||||
*/
|
||||
public function npgettext($context, $singular, $plural, $number)
|
||||
{
|
||||
public function npgettext(
|
||||
string $context,
|
||||
string $singular,
|
||||
string $plural,
|
||||
int $number
|
||||
): string {
|
||||
$key = $context . chr(4) . $singular;
|
||||
$ret = $this->ngettext($key, $plural, $number);
|
||||
if (strpos($ret, "\004") !== false) {
|
||||
|
||||
@@ -41,7 +41,7 @@ class StreamReader
|
||||
* @param int $bytes bytes to read
|
||||
* @return bool dummy false
|
||||
*/
|
||||
public function read($bytes)
|
||||
public function read(int $bytes): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class StreamReader
|
||||
* @param int $position seek to position
|
||||
* @return bool dummy false
|
||||
*/
|
||||
public function seekto($position)
|
||||
public function seekto(int $position): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ class StreamReader
|
||||
* returns current position
|
||||
* @return bool dummy false
|
||||
*/
|
||||
public function currentpos()
|
||||
public function currentpos(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ class StreamReader
|
||||
* returns length of entire stream (limit for seekto()s)
|
||||
* @return bool dummy false
|
||||
*/
|
||||
public function length()
|
||||
public function length(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class StringReader
|
||||
* constructor for string reader
|
||||
* @param string $str basic string
|
||||
*/
|
||||
public function __construct($str = '')
|
||||
public function __construct(string $str = '')
|
||||
{
|
||||
$this->sr_str = $str;
|
||||
$this->sr_pos = 0;
|
||||
@@ -46,7 +46,7 @@ class StringReader
|
||||
* @param int $bytes bytes to read in string
|
||||
* @return string data read in length of bytes as string
|
||||
*/
|
||||
public function read($bytes)
|
||||
public function read(int $bytes): string
|
||||
{
|
||||
$data = substr($this->sr_str, $this->sr_pos, $bytes);
|
||||
$this->sr_pos += $bytes;
|
||||
@@ -62,7 +62,7 @@ class StringReader
|
||||
* @param int $pos position in string
|
||||
* @return int new position in string after seek
|
||||
*/
|
||||
public function seekto($pos)
|
||||
public function seekto(int $pos): int
|
||||
{
|
||||
$this->sr_pos = $pos;
|
||||
if (strlen($this->sr_str) < $this->sr_pos) {
|
||||
@@ -75,7 +75,7 @@ class StringReader
|
||||
* get current position in string
|
||||
* @return int position in string
|
||||
*/
|
||||
public function currentpos()
|
||||
public function currentpos(): int
|
||||
{
|
||||
return $this->sr_pos;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ class StringReader
|
||||
* get length of string
|
||||
* @return int return length of assigned string
|
||||
*/
|
||||
public function length()
|
||||
public function length(): int
|
||||
{
|
||||
return strlen($this->sr_str);
|
||||
}
|
||||
|
||||
@@ -40,104 +40,530 @@ use CoreLibs\Language\Core\GetTextReader;
|
||||
|
||||
class L10n
|
||||
{
|
||||
/** @var string */
|
||||
private $lang = '';
|
||||
/** @var string */
|
||||
/** @var string the current locale */
|
||||
private $locale = '';
|
||||
/** @var string the default selected/active domain */
|
||||
private $domain = '';
|
||||
/** @var array<string,array<string,GetTextReader>> locale > domain = translator */
|
||||
private $domains = [];
|
||||
/** @var array<string,string> bound paths for domains */
|
||||
private $paths = ['' => './'];
|
||||
/** @var string the full path to the mo file to loaded */
|
||||
private $mofile = '';
|
||||
/** @var FileReader|bool */
|
||||
private $input;
|
||||
/** @var GetTextReader */
|
||||
/** @var string base path to search level */
|
||||
private $base_locale_path = '';
|
||||
/** @var string dynamic set path to where the mo file is actually */
|
||||
private $base_content_path = '';
|
||||
/** @var bool if load of mo file was unsuccessful */
|
||||
private $load_failure = false;
|
||||
|
||||
/** @var FileReader|bool reader class for file reading, false for short circuit */
|
||||
private $input = false;
|
||||
/** @var GetTextReader reader class for MO data */
|
||||
private $l10n;
|
||||
/**
|
||||
* @static
|
||||
* @var L10n self class
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* class constructor call for language getstring
|
||||
* @param string $lang language name (optional), fallback is en
|
||||
* @param string $path path, if empty fallback on default internal path
|
||||
* if locale is not empty will load translation
|
||||
* else getTranslator needs to be called
|
||||
*
|
||||
* @param string $locale language name, default empty string
|
||||
* will return self instance
|
||||
* @param string $path path, if empty fallback on default internal path
|
||||
* @param string $domain override CONTENT_PATH . $encoding name for mo file
|
||||
* @param bool $legacy default true, if set to true, will look in the old
|
||||
* folder format lang/ CONTENT_PATH / $lang . mo
|
||||
*/
|
||||
public function __construct(string $lang = '', string $path = '')
|
||||
{
|
||||
if (!$lang) {
|
||||
$this->lang = 'en';
|
||||
} else {
|
||||
$this->lang = $lang;
|
||||
public function __construct(
|
||||
string $locale = '',
|
||||
string $path = '',
|
||||
string $domain = '',
|
||||
bool $legacy = true
|
||||
) {
|
||||
// load the mo file if locale is not empty
|
||||
if (!empty($locale)) {
|
||||
$this->getTranslator($locale, $path, $domain, $legacy);
|
||||
}
|
||||
|
||||
// override path check
|
||||
if (!is_dir($path)) {
|
||||
$path = BASE . INCLUDES . LANG . CONTENT_PATH;
|
||||
}
|
||||
|
||||
$this->mofile = $path . $this->lang . ".mo";
|
||||
|
||||
// check if get a readable mofile
|
||||
if (is_readable($this->mofile)) {
|
||||
$this->input = new FileReader($this->mofile);
|
||||
} else {
|
||||
$this->input = false;
|
||||
}
|
||||
$this->l10n = new GetTextReader($this->input);
|
||||
}
|
||||
|
||||
/**
|
||||
* reloads the mofile, if the location of the lang file changes
|
||||
* @param string $lang language to reload data
|
||||
* @param string $path optional path, if not set fallback on internal
|
||||
* @return bool successfull reload true/false
|
||||
* Returns the singleton L10n object.
|
||||
* For function wrapper use
|
||||
*
|
||||
* @return L10n object
|
||||
*/
|
||||
public function l10nReloadMOfile(string $lang, string $path = ''): bool
|
||||
public static function getInstance(): L10n
|
||||
{
|
||||
$success = false;
|
||||
$old_mofile = $this->mofile;
|
||||
$old_lang = $this->lang;
|
||||
|
||||
$this->lang = $lang;
|
||||
|
||||
// override path check
|
||||
if (!is_dir($path)) {
|
||||
$path = BASE . INCLUDES . LANG . CONTENT_PATH;
|
||||
/** @phpstan-ignore-next-line */
|
||||
if (empty(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
$this->mofile = $path . $this->lang . ".mo";
|
||||
/**
|
||||
* Loads global localization functions.
|
||||
* prefixed with double underscore
|
||||
* eg: gettext -> __gettext
|
||||
*/
|
||||
public static function loadFunctions(): void
|
||||
{
|
||||
require_once __DIR__ . '/l10n_functions.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* legacy loader name for getTranslator
|
||||
* instead of returning the GetTextReader object it returns
|
||||
* true or false for successful load.
|
||||
* NOTE: some time down the road this will be deprecated
|
||||
*
|
||||
* @param string $locale
|
||||
* @param string $path
|
||||
* @param string $domain
|
||||
* @param bool $legacy
|
||||
* @return bool Returns true for successfull load, false for error
|
||||
*/
|
||||
public function l10nReloadMOfile(
|
||||
string $locale,
|
||||
string $path = '',
|
||||
string $domain = '',
|
||||
bool $legacy = true
|
||||
): bool {
|
||||
$this->getTranslator($locale, $path, $domain, $legacy);
|
||||
return $this->load_failure ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the mo file base on path, locale and domain set
|
||||
*
|
||||
* @param string $locale language name (optional), fallback is en
|
||||
* @param string $path path, if empty fallback on default internal path
|
||||
* @param string $domain override CONTENT_PATH . $encoding name for mo file
|
||||
* @param bool $legacy default true, if set to true, will look in the old
|
||||
* folder format lang/ CONTENT_PATH / $lang . mo
|
||||
* @return GetTextReader the main gettext reader object
|
||||
*/
|
||||
public function getTranslator(
|
||||
string $locale = '',
|
||||
string $path = '',
|
||||
string $domain = '',
|
||||
bool $legacy = false
|
||||
): GetTextReader {
|
||||
// set local if not from parameter
|
||||
if (empty($locale)) {
|
||||
$locale = $this->locale;
|
||||
}
|
||||
// set domain if not given
|
||||
if (empty($domain)) {
|
||||
$domain = $this->domain;
|
||||
}
|
||||
// store old settings
|
||||
$old_mofile = $this->mofile;
|
||||
$old_lang = $this->locale;
|
||||
$old_domain = $this->domain;
|
||||
$old_base_locale_path = $this->base_locale_path;
|
||||
$old_base_content_path = $this->base_content_path;
|
||||
|
||||
// legacy or new type
|
||||
// legacy will use the old lang/content/file.mo type as default
|
||||
// if path is not set, also locale is the file name
|
||||
// for new type it follows the gettext spec and path is just the
|
||||
// base folder where the mo files will be searched
|
||||
if ($legacy === true) {
|
||||
if (!is_dir($path)) {
|
||||
$this->base_locale_path = BASE . INCLUDES . LANG;
|
||||
$this->base_content_path = CONTENT_PATH;
|
||||
$path = $this->base_locale_path . $this->base_content_path;
|
||||
}
|
||||
$this->mofile = $path . $locale . ".mo";
|
||||
} else {
|
||||
// if new path is a dir
|
||||
// 1) from a previous set domain
|
||||
// 2) from method option as is
|
||||
// 3) fallback if BASE/INCLUDES/LOCALE set
|
||||
// 4) current dir
|
||||
if (!empty($this->paths[$domain]) && is_dir($this->paths[$domain])) {
|
||||
$this->base_locale_path = $this->paths[$domain];
|
||||
} elseif (is_dir($path)) {
|
||||
$this->base_locale_path = $path;
|
||||
} elseif (
|
||||
defined('BASE') && defined('INCLUDES') && defined('LOCALE')
|
||||
) {
|
||||
// set fallback base path if constant set
|
||||
$this->base_locale_path = BASE . INCLUDES . LOCALE;
|
||||
} else {
|
||||
$this->base_locale_path = './';
|
||||
}
|
||||
// now we loop over lang compositions to get the base path
|
||||
// then we check
|
||||
$locales = $this->listLocales($locale);
|
||||
foreach ($locales as $_locale) {
|
||||
$this->base_content_path = $_locale . DIRECTORY_SEPARATOR
|
||||
. 'LC_MESSAGES' . DIRECTORY_SEPARATOR;
|
||||
$this->mofile = $this->base_locale_path
|
||||
. $this->base_content_path
|
||||
. $domain . '.mo';
|
||||
if (file_exists($this->mofile)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if get a readable mofile
|
||||
if (is_readable($this->mofile)) {
|
||||
// locale and domain current wanted
|
||||
$this->locale = $locale;
|
||||
$this->domain = $domain;
|
||||
// set empty domains path with current locale
|
||||
if (empty($this->domains[$locale])) {
|
||||
$this->domains[$locale] = [];
|
||||
}
|
||||
// store current base path (without locale, etc)
|
||||
if (empty($this->paths[$domain])) {
|
||||
$this->paths[$domain] = $this->base_locale_path;
|
||||
}
|
||||
// file reader and mo reader
|
||||
$this->input = new FileReader($this->mofile);
|
||||
$this->l10n = new GetTextReader($this->input);
|
||||
// we successfully loaded
|
||||
$success = true;
|
||||
} else {
|
||||
// if short circuit is true, we failed to have a translator loaded
|
||||
$this->load_failure = $this->l10n->getShortCircuit();
|
||||
// below is not used at the moment, but can be to avoid reloading
|
||||
$this->domains[$this->locale][$domain] = $this->l10n;
|
||||
} elseif (!empty($old_mofile)) {
|
||||
// mo file not readable
|
||||
$this->load_failure = true;
|
||||
// else fall back to the old ones
|
||||
$this->mofile = $old_mofile;
|
||||
$this->lang = $old_lang;
|
||||
$this->locale = $old_lang;
|
||||
$this->domain = $old_domain;
|
||||
$this->base_locale_path = $old_base_locale_path;
|
||||
$this->base_content_path = $old_base_content_path;
|
||||
} else {
|
||||
// mo file not readable, no previous mo file set, set short circuit
|
||||
$this->load_failure = true;
|
||||
// dummy
|
||||
$this->l10n = new GetTextReader($this->input);
|
||||
}
|
||||
return $success;
|
||||
return $this->l10n;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* return current set GetTextReader or return the one for given
|
||||
* domain name if set
|
||||
* This can be used to access all the public methods from the
|
||||
* GetTextReader
|
||||
*
|
||||
* @param string $domain optional domain name
|
||||
* @return GetTextReader
|
||||
*/
|
||||
public function getTranslatorClass(string $domain = ''): GetTextReader
|
||||
{
|
||||
if (!empty($domain) && !empty($this->domains[$this->locale][$domain])) {
|
||||
return $this->domains[$this->locale][$domain];
|
||||
}
|
||||
// if null return short circuit version
|
||||
if ($this->l10n === null) {
|
||||
return new GetTextReader($this->input);
|
||||
}
|
||||
return $this->l10n;
|
||||
}
|
||||
|
||||
/**
|
||||
* original:
|
||||
* vendor/phpmyadmin/motranslator/src/Loader.php
|
||||
*
|
||||
* Returns array with all possible locale combinations based on the
|
||||
* given locale name
|
||||
*
|
||||
* I.e. for sr_CS.UTF-8@latin, look through all of
|
||||
* sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr.
|
||||
*
|
||||
* @param string $locale Locale string
|
||||
* @return array<string> List of locale path parts that can be possible
|
||||
*/
|
||||
public static function listLocales(string $locale): array
|
||||
{
|
||||
$locale_list = [];
|
||||
|
||||
if (empty($locale)) {
|
||||
return $locale_list;
|
||||
}
|
||||
// is matching regex
|
||||
if (
|
||||
!preg_match(
|
||||
// language code
|
||||
'/^(?P<lang>[a-z]{2,3})'
|
||||
// country code
|
||||
. '(?:_(?P<country>[A-Z]{2}))?'
|
||||
// charset
|
||||
. '(?:\\.(?P<charset>[-A-Za-z0-9_]+))?'
|
||||
// @ modifier
|
||||
. '(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/',
|
||||
$locale,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
// not matching, return as is
|
||||
return [$locale];
|
||||
}
|
||||
// do matching run
|
||||
$lang = $matches['lang'] ?? null;
|
||||
$country = $matches['country'] ?? null;
|
||||
$charset = $matches['charset'] ?? null;
|
||||
$modifier = $matches['modifier'] ?? null;
|
||||
// we need to add all possible cominations from not null set
|
||||
// entries to the list, from longest to shortest
|
||||
// %s_%s.%s@%s (lang _ country . encoding @ suffix)
|
||||
// %s_%s@%s (lang _ country @ suffix)
|
||||
// %s@%s (lang @ suffix)
|
||||
// %s_%s.%s (lang _ country . encoding)
|
||||
// %s_%s (lang _ country)
|
||||
// %s (lang)
|
||||
|
||||
// if lang is set
|
||||
if ($lang) {
|
||||
// modifier group
|
||||
if ($modifier) {
|
||||
if ($country) {
|
||||
if ($charset) {
|
||||
array_push(
|
||||
$locale_list,
|
||||
sprintf('%s_%s.%s@%s', $lang, $country, $charset, $modifier)
|
||||
);
|
||||
}
|
||||
|
||||
array_push(
|
||||
$locale_list,
|
||||
sprintf('%s_%s@%s', $lang, $country, $modifier)
|
||||
);
|
||||
} elseif ($charset) {
|
||||
array_push(
|
||||
$locale_list,
|
||||
sprintf('%s.%s@%s', $lang, $charset, $modifier)
|
||||
);
|
||||
}
|
||||
|
||||
array_push(
|
||||
$locale_list,
|
||||
sprintf('%s@%s', $lang, $modifier)
|
||||
);
|
||||
}
|
||||
// country group
|
||||
if ($country) {
|
||||
if ($charset) {
|
||||
array_push(
|
||||
$locale_list,
|
||||
sprintf('%s_%s.%s', $lang, $country, $charset)
|
||||
);
|
||||
}
|
||||
|
||||
array_push(
|
||||
$locale_list,
|
||||
sprintf('%s_%s', $lang, $country)
|
||||
);
|
||||
} elseif ($charset) {
|
||||
array_push(
|
||||
$locale_list,
|
||||
sprintf('%s.%s', $lang, $charset)
|
||||
);
|
||||
}
|
||||
// lang only
|
||||
array_push($locale_list, $lang);
|
||||
}
|
||||
|
||||
// If the locale name doesn't match POSIX style, just include it as-is.
|
||||
if (!in_array($locale, $locale_list)) {
|
||||
array_push($locale_list, $locale);
|
||||
}
|
||||
|
||||
return $locale_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* tries to detect the locale set in the following order:
|
||||
* - globals: LOCALE
|
||||
* - globals: LANG
|
||||
* - env: LC_ALL
|
||||
* - env: LC_MESSAGES
|
||||
* - env: LANG
|
||||
* if nothing set, returns 'en' as default
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function detectLocale(): string
|
||||
{
|
||||
// globals
|
||||
foreach (['LOCALE', 'LANG'] as $global) {
|
||||
if (!empty($GLOBALS[$global])) {
|
||||
return $GLOBALS[$global];
|
||||
}
|
||||
}
|
||||
// enviroment
|
||||
foreach (['LC_ALL', 'LC_MESSAGES', 'LANG'] as $env) {
|
||||
$locale = getenv($env);
|
||||
if ($locale !== false && !empty($locale)) {
|
||||
return $locale;
|
||||
}
|
||||
}
|
||||
return 'en';
|
||||
}
|
||||
|
||||
/************
|
||||
* INTERNAL VAR SET/GET
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the path for a domain.
|
||||
* must be set before running l10nReloadMOfile
|
||||
*
|
||||
* @param string $domain Domain name
|
||||
* @param string $path Path where to find locales
|
||||
*/
|
||||
public function setTextDomain(string $domain, string $path): void
|
||||
{
|
||||
$this->paths[$domain] = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* return set path for given domain
|
||||
* if not found return false
|
||||
*
|
||||
* @param string $domain
|
||||
* @return string|bool
|
||||
*/
|
||||
public function getTextDomain(string $domain)
|
||||
{
|
||||
return $this->paths[$domain] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the default domain.
|
||||
*
|
||||
* @param string $domain Domain name
|
||||
*/
|
||||
public function setDomain(string $domain): void
|
||||
{
|
||||
$this->domain = $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* return current set domain name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDomain(): string
|
||||
{
|
||||
return $this->domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets a requested locale.
|
||||
*
|
||||
* @param string $locale Locale name
|
||||
* @return string Set or current locale
|
||||
*/
|
||||
public function setLocale(string $locale): string
|
||||
{
|
||||
if (!empty($locale)) {
|
||||
$this->locale = $locale;
|
||||
}
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current set locale
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current set language
|
||||
*
|
||||
* @return string current set language string
|
||||
* @deprecated Use getLocale()
|
||||
*/
|
||||
public function __getLang(): string
|
||||
{
|
||||
return $this->lang;
|
||||
return $this->getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* get current set mo file
|
||||
*
|
||||
* @return string current set mo language file
|
||||
*/
|
||||
public function __getMoFile(): string
|
||||
public function getMoFile(): string
|
||||
{
|
||||
return $this->mofile;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current set mo file
|
||||
*
|
||||
* @return string current set mo language file
|
||||
* @deprecated Use getMoFile()
|
||||
*/
|
||||
public function __getMoFile(): string
|
||||
{
|
||||
return $this->getMoFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current base path in which we search
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseLocalePath(): string
|
||||
{
|
||||
return $this->base_locale_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* the path below the base path to where the mo file is located
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseContentPath(): string
|
||||
{
|
||||
return $this->base_content_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current load error status
|
||||
* if true then the mo file failed to load
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getLoadError(): bool
|
||||
{
|
||||
return $this->load_failure;
|
||||
}
|
||||
|
||||
/************
|
||||
* TRANSLATION METHODS
|
||||
*/
|
||||
|
||||
/**
|
||||
* translates a string and returns translated text
|
||||
*
|
||||
* @param string $text text to translate
|
||||
* @return string translated text
|
||||
*/
|
||||
public function __(string $text): string
|
||||
{
|
||||
// fallback passthrough
|
||||
if ($this->l10n === null) {
|
||||
return $text;
|
||||
}
|
||||
return $this->l10n->translate($text);
|
||||
}
|
||||
|
||||
@@ -145,32 +571,75 @@ class L10n
|
||||
* prints translated string out to the screen
|
||||
* @param string $text text to translate
|
||||
* @return void has no return
|
||||
* @deprecated use echo __() instead
|
||||
*/
|
||||
public function __e(string $text): void
|
||||
{
|
||||
// fallback passthrough
|
||||
if ($this->l10n === null) {
|
||||
echo $text;
|
||||
}
|
||||
echo $this->l10n->translate($text);
|
||||
}
|
||||
|
||||
// Return the plural form.
|
||||
/**
|
||||
* Return the plural form.
|
||||
* @param string $single string for single word
|
||||
* @param string $plural string for plural word
|
||||
* @param int|float $number number value
|
||||
* @return string translated plural string
|
||||
*
|
||||
* @param string $single string for single word
|
||||
* @param string $plural string for plural word
|
||||
* @param int $number number value
|
||||
* @return string translated plural string
|
||||
*/
|
||||
public function __n(string $single, string $plural, $number): string
|
||||
public function __n(string $single, string $plural, int $number): string
|
||||
{
|
||||
// in case nothing got set yet, this is fallback
|
||||
if ($this->l10n === null) {
|
||||
return $number > 1 ? $plural : $single;
|
||||
}
|
||||
return $this->l10n->ngettext($single, $plural, $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* context translation via msgctxt
|
||||
*
|
||||
* @param string $context context string
|
||||
* @param string $text text to translate
|
||||
* @return string
|
||||
*/
|
||||
public function __p(string $context, string $text): string
|
||||
{
|
||||
if ($this->l10n === null) {
|
||||
return $text;
|
||||
}
|
||||
return $this->l10n->pgettext($context, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* context translation via msgctxt
|
||||
*
|
||||
* @param string $context context string
|
||||
* @param string $single string for single word
|
||||
* @param string $plural string for plural word
|
||||
* @param int $number number value
|
||||
* @return string
|
||||
*/
|
||||
public function __pn(string $context, string $single, string $plural, int $number): string
|
||||
{
|
||||
if ($this->l10n === null) {
|
||||
return $number > 1 ? $plural : $single;
|
||||
}
|
||||
return $this->l10n->npgettext($context, $single, $plural, $number);
|
||||
}
|
||||
|
||||
// alias functions to mimic gettext calls
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* alias for gettext,
|
||||
* calls __
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
* @deprecated Use __()
|
||||
*/
|
||||
public function gettext(string $text): string
|
||||
{
|
||||
@@ -178,22 +647,24 @@ class L10n
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* alias for ngettext
|
||||
* calls __n
|
||||
*
|
||||
* @param string $single
|
||||
* @param string $plural
|
||||
* @param int|float $number
|
||||
* @param int $number
|
||||
* @return string
|
||||
* @deprecated Use __n()
|
||||
*/
|
||||
public function ngettext(string $single, string $plural, $number): string
|
||||
public function ngettext(string $single, string $plural, int $number): string
|
||||
{
|
||||
return $this->__n($single, $plural, $number);
|
||||
}
|
||||
|
||||
// TODO: dgettext(string $domain, string $message): string
|
||||
// TODO: dngettext(string $domain, string $singular, string $plural, int $count): string
|
||||
// TODO: dcgettext(string $domain, string $message, int $category): string
|
||||
// TODO: dcngettext(string $domain, string $singular, string $plural, int $count, int $category): string
|
||||
// TODO: dpgettext(string $domain, string $message, int $category): string
|
||||
// TODO: dpngettext(string $domain, string $singular, string $plural, int $count, int $category): string
|
||||
}
|
||||
|
||||
// __END__
|
||||
|
||||
208
www/lib/CoreLibs/Language/l10n_functions.php
Normal file
208
www/lib/CoreLibs/Language/l10n_functions.php
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use CoreLibs\Language\L10n;
|
||||
|
||||
/**
|
||||
* Sets a requested locale.
|
||||
*
|
||||
* @param int $category Locale category, ignored
|
||||
* @param string $locale Locale name
|
||||
*
|
||||
* @return string Set or current locale
|
||||
*/
|
||||
function __setlocale(int $category, string $locale): string
|
||||
{
|
||||
return L10n::getInstance()->setLocale($locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the path for a domain.
|
||||
*
|
||||
* @param string $domain Domain name
|
||||
* @param string $path Path where to find locales
|
||||
*/
|
||||
function __bindtextdomain(string $domain, string $path): void
|
||||
{
|
||||
L10n::getInstance()->setTextDomain($domain, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy compatibility function, MoTranslator assumes
|
||||
* everything is using same character set on input and
|
||||
* output.
|
||||
*
|
||||
* Generally it is wise to output in UTF-8 and have
|
||||
* mo files in UTF-8.
|
||||
*
|
||||
* @param string $domain Domain where to set character set
|
||||
* @param string $codeset Character set to set
|
||||
*/
|
||||
function __bind_textdomain_codeset(string $domain, string $codeset): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default domain.
|
||||
*
|
||||
* @param string $domain Domain name
|
||||
*/
|
||||
function __textdomain(string $domain): void
|
||||
{
|
||||
L10n::getInstance()->setDomain($domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a string.
|
||||
*
|
||||
* @param string $msgid String to be translated
|
||||
*
|
||||
* @return string translated string (or original, if not found)
|
||||
*/
|
||||
function __gettext(string $msgid): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator()->gettext(
|
||||
$msgid
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a string, alias for _gettext.
|
||||
*
|
||||
* @param string $msgid String to be translated
|
||||
*
|
||||
* @return string translated string (or original, if not found)
|
||||
*/
|
||||
function __(string $msgid): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator()->gettext(
|
||||
$msgid
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plural version of gettext.
|
||||
*
|
||||
* @param string $msgid Single form
|
||||
* @param string $msgidPlural Plural form
|
||||
* @param int $number Number of objects
|
||||
*
|
||||
* @return string translated plural form
|
||||
*/
|
||||
function __ngettext(string $msgid, string $msgidPlural, int $number): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator()->ngettext(
|
||||
$msgid,
|
||||
$msgidPlural,
|
||||
$number
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate with context.
|
||||
*
|
||||
* @param string $msgctxt Context
|
||||
* @param string $msgid String to be translated
|
||||
*
|
||||
* @return string translated plural form
|
||||
*/
|
||||
function __pgettext(string $msgctxt, string $msgid): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator()->pgettext(
|
||||
$msgctxt,
|
||||
$msgid
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plural version of pgettext.
|
||||
*
|
||||
* @param string $msgctxt Context
|
||||
* @param string $msgid Single form
|
||||
* @param string $msgidPlural Plural form
|
||||
* @param int $number Number of objects
|
||||
*
|
||||
* @return string translated plural form
|
||||
*/
|
||||
function __npgettext(string $msgctxt, string $msgid, string $msgidPlural, int $number): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator()->npgettext(
|
||||
$msgctxt,
|
||||
$msgid,
|
||||
$msgidPlural,
|
||||
$number
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a string.
|
||||
*
|
||||
* @param string $domain Domain to use
|
||||
* @param string $msgid String to be translated
|
||||
*
|
||||
* @return string translated string (or original, if not found)
|
||||
*/
|
||||
function __dgettext(string $domain, string $msgid): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator('', '', $domain)->gettext(
|
||||
$msgid
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plural version of gettext.
|
||||
*
|
||||
* @param string $domain Domain to use
|
||||
* @param string $msgid Single form
|
||||
* @param string $msgidPlural Plural form
|
||||
* @param int $number Number of objects
|
||||
*
|
||||
* @return string translated plural form
|
||||
*/
|
||||
function __dngettext(string $domain, string $msgid, string $msgidPlural, int $number): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator('', '', $domain)->ngettext(
|
||||
$msgid,
|
||||
$msgidPlural,
|
||||
$number
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate with context.
|
||||
*
|
||||
* @param string $domain Domain to use
|
||||
* @param string $msgctxt Context
|
||||
* @param string $msgid String to be translated
|
||||
*
|
||||
* @return string translated plural form
|
||||
*/
|
||||
function __dpgettext(string $domain, string $msgctxt, string $msgid): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator('', '', $domain)->pgettext(
|
||||
$msgctxt,
|
||||
$msgid
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plural version of pgettext.
|
||||
*
|
||||
* @param string $domain Domain to use
|
||||
* @param string $msgctxt Context
|
||||
* @param string $msgid Single form
|
||||
* @param string $msgidPlural Plural form
|
||||
* @param int $number Number of objects
|
||||
*
|
||||
* @return string translated plural form
|
||||
*/
|
||||
function __dnpgettext(string $domain, string $msgctxt, string $msgid, string $msgidPlural, int $number): string
|
||||
{
|
||||
return L10n::getInstance()->getTranslator('', '', $domain)->npgettext(
|
||||
$msgctxt,
|
||||
$msgid,
|
||||
$msgidPlural,
|
||||
$number
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user