From 02cc25157a14127bc94649f61c086878e13b980c Mon Sep 17 00:00:00 2001 From: Rhilip Date: Sun, 29 Sep 2019 22:32:41 +0800 Subject: [PATCH] feat(i18n): Use symfony/translation and JSON format for locale --- CHANGELOG.md | 1 + application/Lang/en.php | 30 --- application/Lang/zh_CN.php | 29 --- composer.json | 4 +- composer.lock | 434 ++++++++++++++++++++++++++++++++- config/application.php | 162 ++++++------ framework/Component/I18n.php | 150 +++++------- framework/functions.php | 4 +- templates/index.php | 2 +- templates/layout/nav_user.php | 26 +- templates/torrents/search.php | 4 +- translations/locale-en.json | 20 ++ translations/locale-zh_CN.json | 20 ++ var/translation/.gitignore | 2 + 14 files changed, 637 insertions(+), 251 deletions(-) delete mode 100644 application/Lang/en.php delete mode 100644 application/Lang/zh_CN.php create mode 100644 translations/locale-en.json create mode 100644 translations/locale-zh_CN.json create mode 100644 var/translation/.gitignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 50e498d..0463e9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - **Validator:** Upgrade siriusphp/validation to 2.3 (eb039eb) ### Docs +- **Release:** Version 'v0.1.6-alpha' (e5a6e3e) - **bin:** Add doc for bin/rid-httpd (59e0828) - **template:** Add git commit hash in `CHANGELOG.md` (76bc527) diff --git a/application/Lang/en.php b/application/Lang/en.php deleted file mode 100644 index 866b22c..0000000 --- a/application/Lang/en.php +++ /dev/null @@ -1,30 +0,0 @@ -=7.0" @@ -74,7 +80,13 @@ "type": "zip", "url": "https://api.github.com/repos/firebase/php-jwt/zipball/9984a4d3a32ae7673d6971ea00bae9d0a1abba0e", "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3.0" @@ -120,7 +132,13 @@ "type": "zip", "url": "https://api.github.com/repos/thephpleague/plates/zipball/b1684b6f127714497a0ef927ce42c0b44b45a8af", "reference": "b1684b6f127714497a0ef927ce42c0b44b45a8af", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": "^5.3 | ^7.0" @@ -175,7 +193,13 @@ "type": "zip", "url": "https://api.github.com/repos/milesj/decoda/zipball/9817fd5abbd742384f59831d8a5953b01803b45d", "reference": "9817fd5abbd742384f59831d8a5953b01803b45d", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-mbstring": "*", @@ -229,7 +253,13 @@ "type": "zip", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/0c41a36d4508d470e376498c1c0c527aa36a2d59", "reference": "0c41a36d4508d470e376498c1c0c527aa36a2d59", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-ctype": "*", @@ -295,7 +325,13 @@ "type": "zip", "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3.0" @@ -345,7 +381,13 @@ "type": "zip", "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3.0" @@ -392,7 +434,13 @@ "type": "zip", "url": "https://api.github.com/repos/siriusphp/validation/zipball/fa93b302802616b1dcf7e38244a70e324c121fb4", "reference": "fa93b302802616b1dcf7e38244a70e324c121fb4", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3" @@ -438,7 +486,13 @@ "type": "zip", "url": "https://api.github.com/repos/soundasleep/html2text/zipball/3243a7107878a61685d2eccf99918d6479e039fc", "reference": "3243a7107878a61685d2eccf99918d6479e039fc", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "ext-dom": "*", @@ -476,6 +530,132 @@ ], "time": "2019-02-15T01:44:54+00:00" }, + { + "name": "symfony/config", + "version": "v4.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "07d49c0f823e0bc367c6d84e35b61419188a5ece" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/07d49c0f823e0bc367c6d84e35b61419188a5ece", + "reference": "07d49c0f823e0bc367c6d84e35b61419188a5ece", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1.3", + "symfony/filesystem": "~3.4|~4.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/finder": "~3.4|~4.0", + "symfony/messenger": "~4.1", + "symfony/yaml": "~3.4|~4.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2019-08-26T08:26:39+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2019-08-20T14:07:54+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.12.0", @@ -488,7 +668,13 @@ "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", "reference": "550ebaac289296ce228a706d0867afc34687e3f4", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": ">=5.3.3" @@ -534,6 +720,216 @@ ], "time": "2019-08-06T08:03:45+00:00" }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/translation", + "version": "v4.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "28498169dd334095fa981827992f3a24d50fed0f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/28498169dd334095fa981827992f3a24d50fed0f", + "reference": "28498169dd334095fa981827992f3a24d50fed0f", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^1.1.6" + }, + "conflict": { + "symfony/config": "<3.4", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "provide": { + "symfony/translation-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/console": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/finder": "~2.8|~3.0|~4.0", + "symfony/http-kernel": "~3.4|~4.0", + "symfony/intl": "~3.4|~4.0", + "symfony/service-contracts": "^1.1.2", + "symfony/var-dumper": "~3.4|~4.0", + "symfony/yaml": "~3.4|~4.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2019-08-26T08:55:16+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v1.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "325b17c24f3ee23cbecfa63ba809c6d89b5fa04a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/325b17c24f3ee23cbecfa63ba809c6d89b5fa04a", + "reference": "325b17c24f3ee23cbecfa63ba809c6d89b5fa04a", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1.3" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-08-02T12:15:04+00:00" + }, { "name": "vlucas/phpdotenv", "version": "v3.6.0", @@ -546,7 +942,13 @@ "type": "zip", "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1bdf24f065975594f6a117f0f1f6cabf1333b156", "reference": "1bdf24f065975594f6a117f0f1f6cabf1333b156", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "require": { "php": "^5.4 || ^7.0", @@ -605,7 +1007,13 @@ "type": "zip", "url": "https://api.github.com/repos/wudi/swoole-ide-helper/zipball/fceabb51fca645166fdc3d885bb582eb3352335e", "reference": "fceabb51fca645166fdc3d885bb582eb3352335e", - "shasum": "" + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] }, "type": "library", "notification-url": "https://packagist.org/downloads/", diff --git a/config/application.php b/config/application.php index e99b475..81fff2a 100644 --- a/config/application.php +++ b/config/application.php @@ -11,30 +11,30 @@ return [ // 基础路径 - 'basePath' => dirname(__DIR__), + 'basePath' => dirname(__DIR__), // 控制器命名空间 'controllerNamespace' => 'App\Controllers', // 全局中间件 - 'middleware' => [ + 'middleware' => [ App\Middleware\IpBanMiddleware::class ], // 组件配置 - 'components' => [ + 'components' => [ // 路由 - 'route' => [ + 'route' => [ // 类路径 - 'class' => Rid\Http\Route::class, + 'class' => Rid\Http\Route::class, // 默认变量规则 'defaultPattern' => '[\w-]+', // 路由变量规则 - 'patterns' => [ + 'patterns' => [ 'id' => '\d+' ], // 路由规则 - 'rules' => [ + 'rules' => [ 'GET tracker/{tracker_action}' => ['tracker', 'index'], 'GET captcha' => ['captcha', 'index'], 'GET maintenance' => ['maintenance', 'index'], @@ -53,80 +53,42 @@ ], // 请求 - 'request' => [ + 'request' => [ 'class' => Rid\Http\Request::class, ], // 响应 'response' => [ // 类路径 - 'class' => Rid\Http\Response::class, + 'class' => Rid\Http\Response::class, // 默认输出格式 'defaultFormat' => Rid\Http\Response::FORMAT_HTML, ], // 错误 - 'error' => [ - 'class' => Rid\Http\Error::class, + 'error' => [ + 'class' => Rid\Http\Error::class, 'format' => Rid\Http\Error::FORMAT_HTML, ], // 日志 'log' => [ - 'class' => Rid\Component\Log::class, // 类路径 - 'dir' => 'logs', // 日志目录 - 'rotate' => Rid\Component\Log::ROTATE_DAY, // 日志轮转类型 + 'class' => Rid\Component\Log::class, // 类路径 + 'dir' => 'logs', // 日志目录 + 'rotate' => Rid\Component\Log::ROTATE_DAY, // 日志轮转类型 'maxFileSize' => 0, // 最大文件尺寸 ], - // Session - 'session' => [ - // 类路径 - 'class' => Rid\Http\Session::class, - // 保存的Key前缀 - 'saveKeyPrefix' => 'Session:', - // 生存时间 - 'maxLifetime' => 7200, - // session键名 - 'name' => 'session_id', - // 过期时间 - 'cookieExpires' => 0, - // 有效的服务器路径 - 'cookiePath' => '/', - // 有效域名/子域名 - 'cookieDomain' => '', - // 仅通过安全的 HTTPS 连接传给客户端 - 'cookieSecure' => false, - // 仅可通过 HTTP 协议访问 - 'cookieHttpOnly' => false, - ], - - // Cookie - 'cookie' => [ - // 类路径 - 'class' => Rid\Http\Cookie::class, - // 过期时间 - 'expires' => 31536000, - // 有效的服务器路径 - 'path' => '/', - // 有效域名/子域名 - 'domain' => '', - // 仅通过安全的 HTTPS 连接传给客户端 - 'secure' => false, - // 仅可通过 HTTP 协议访问 - 'httpOnly' => false, - ], - // 数据库 - 'pdo' => [ + 'pdo' => [ // 类路径 - 'class' => Rid\Database\Persistent\PDOConnection::class, + 'class' => Rid\Database\Persistent\PDOConnection::class, // 数据源格式 - 'dsn' => env('DATABASE_DSN'), + 'dsn' => env('DATABASE_DSN'), // 数据库用户名 - 'username' => env('DATABASE_USERNAME'), + 'username' => env('DATABASE_USERNAME'), // 数据库密码 - 'password' => env('DATABASE_PASSWORD'), + 'password' => env('DATABASE_PASSWORD'), // 驱动连接选项: http://php.net/manual/zh/pdo.setattribute.php 'driverOptions' => [ // 设置默认的提取模式: \PDO::FETCH_OBJ | \PDO::FETCH_ASSOC @@ -135,13 +97,13 @@ ], // redis - 'redis' => [ + 'redis' => [ // 类路径 - 'class' => Rid\Redis\Persistent\RedisConnection::class, + 'class' => Rid\Redis\Persistent\RedisConnection::class, // 主机 - 'host' => env('REDIS_HOST'), + 'host' => env('REDIS_HOST'), // 端口 - 'port' => env('REDIS_PORT'), + 'port' => env('REDIS_PORT'), // 数据库 'database' => env('REDIS_DATABASE'), // 密码 @@ -151,16 +113,66 @@ ] ], - 'config' => [ - 'class' => Rid\Component\Config::class, + // Session + 'session' => [ + // 类路径 + 'class' => Rid\Http\Session::class, + // 保存的Key前缀 + 'saveKeyPrefix' => 'Session:', + // 生存时间 + 'maxLifetime' => 7200, + // session键名 + 'name' => 'session_id', + // 过期时间 + 'cookieExpires' => 0, + // 有效的服务器路径 + 'cookiePath' => '/', + // 有效域名/子域名 + 'cookieDomain' => '', + // 仅通过安全的 HTTPS 连接传给客户端 + 'cookieSecure' => false, + // 仅可通过 HTTP 协议访问 + 'cookieHttpOnly' => false, + ], + + // Cookie + 'cookie' => [ + // 类路径 + 'class' => Rid\Http\Cookie::class, + // 过期时间 + 'expires' => 31536000, + // 有效的服务器路径 + 'path' => '/', + // 有效域名/子域名 + 'domain' => '', + // 仅通过安全的 HTTPS 连接传给客户端 + 'secure' => false, + // 仅可通过 HTTP 协议访问 + 'httpOnly' => false, ], 'i18n' => [ 'class' => Rid\Component\I18n::class, - 'fileNamespace' => 'App\Lang', 'fallbackLang' => 'en', - 'forcedLang' => null, - 'allowedLangSet' => ['en', 'zh-CN'] + 'cacheDir' => dirname(__DIR__) . '/var/translation', + 'loader' => [ + // 'format' => loaderClass + 'json' => Symfony\Component\Translation\Loader\JsonFileLoader::class + ], + 'resources' => [ + // 'format' => [[$resource, $locale, $domain = null]] + 'json' => [ + [dirname(__DIR__) . '/translations/locale-en.json', 'en'], + [dirname(__DIR__) . '/translations/locale-zh_CN.json', 'zh-CN'], + ], + ], + + 'allowedLangSet' => ['en', 'zh-CN'], + 'forcedLang' => null + ], + + 'config' => [ + 'class' => Rid\Component\Config::class, ], 'site' => [ @@ -173,17 +185,17 @@ ], // 类库配置 - 'libraries' => [ + 'libraries' => [ 'mailer' => [ - 'class' => App\Libraries\Mailer::class, - 'debug' => env('MAILER_DEBUG'), - 'host' => env('MAILER_HOST'), - 'port' => env('MAILER_PORT'), + 'class' => App\Libraries\Mailer::class, + 'debug' => env('MAILER_DEBUG'), + 'host' => env('MAILER_HOST'), + 'port' => env('MAILER_PORT'), 'encryption' => env('MAILER_ENCRYPTION'), - 'username'=> env('MAILER_USERNAME'), - 'password'=> env('MAILER_PASSWORD'), - 'from' => env('MAILER_FROM'), - 'fromname'=> env('MAILER_FROMNAME'), + 'username' => env('MAILER_USERNAME'), + 'password' => env('MAILER_PASSWORD'), + 'from' => env('MAILER_FROM'), + 'fromname' => env('MAILER_FROMNAME'), ], ], ]; diff --git a/framework/Component/I18n.php b/framework/Component/I18n.php index 745dc05..862e602 100644 --- a/framework/Component/I18n.php +++ b/framework/Component/I18n.php @@ -9,6 +9,7 @@ namespace Rid\Component; use Rid\Base\Component; +use Symfony\Component\Translation\Translator; class I18n extends Component { @@ -21,6 +22,10 @@ class I18n extends Component */ public $fileNamespace = '\App\Lang'; + public $cacheDir = ''; + public $loader = []; + public $resources = []; + /** * Allowed language * This is the set of language which is used to limit user languages. No-exist language will not accept. @@ -49,52 +54,65 @@ class I18n extends Component /* * The following properties are only available after calling init(). */ - protected $lastLangs = null; + protected $reqLangs = null; + + protected $_user_lang = null; + + /** @var Translator */ + protected $_translator; public function onRequestBefore() { + $this->reqLangs = null; + $this->_user_lang = null; parent::onRequestBefore(); - $lastLang = null; + } + + public function onInitialize() + { + $this->_translator = new Translator($this->fallbackLang, null, $this->cacheDir, env('APP_DEBUG')); + + // Add Loader + foreach ($this->loader as $format => $loader_type) { + $this->_translator->addLoader($format, new $loader_type()); + } + + // Add Resources + foreach ($this->resources as $format => $resources) { + foreach ($resources as $resource) { + $this->_translator->addResource($format, ...$resource); + } + } } /** * getUserLangs() * Returns the user languages * Normally it returns an array like this: - * 1. Forced language - * 2. Language in $_GET['lang'] - * 3. Language in $_SESSION['lang'] - * 4. HTTP_ACCEPT_LANGUAGE - * 5. Fallback language + * 1. Language in $_GET['lang'] + * 2. Language in user setting + * 3. HTTP_ACCEPT_LANGUAGE * Note: duplicate values are deleted. * - * @param null $reqLang - * @return array with the user languages sorted by priority. + * @return string the user languages sorted by priority. */ - private function getUserLangs($reqLang = null) { - $userLangs = array(); - - // Highest priority: forced language - if ($this->forcedLang != NULL) $userLangs[] = $this->forcedLang; - - // 1st highest priority: required language - if ($reqLang != null) { - $userLangs[] = $reqLang; - - // Lowest priority: fallback - $userLangs[] = $this->fallbackLang; + private function getUserLang() + { + // Return Cache value + if (!is_null($this->_user_lang)) return $this->_user_lang; - $userLangs = array_unique($userLangs); // remove duplicate elements - return $userLangs; - } + // Determine + $judged_langs = array(); - // 2nd highest priority: GET parameter 'lang' - if (!is_null(app()->request->get('lang'))) $userLangs[] = app()->request->get('lang'); + // 1nd highest priority: GET parameter 'lang' + if (!is_null(app()->request->get('lang'))) + $judged_langs[] = app()->request->get('lang'); - // 3rd highest priority: SESSION parameter 'lang' - if (!is_null(app()->auth->getCurUser()->getLang())) $userLangs[] = app()->auth->getCurUser()->getLang(); + // 2rd highest priority: user setting for login user + if (app()->auth->getCurUser() && !is_null(app()->auth->getCurUser()->getLang())) + $judged_langs[] = app()->auth->getCurUser()->getLang(); - // 4th highest priority: HTTP_ACCEPT_LANGUAGE + // 3th highest priority: HTTP_ACCEPT_LANGUAGE if (!is_null(app()->request->header('accept_language'))) { /** * We get headers like this string 'en-US,en;q=0.8,uk;q=0.6' @@ -116,53 +134,20 @@ function ($res, $el) { arsort($prefLocales); foreach ($prefLocales as $part => $q) { - $userLangs[] = $part; + $judged_langs[] = $part; } } - // Lowest priority: fallback - $userLangs[] = $this->fallbackLang; - - $userLangs = array_unique($userLangs); // remove duplicate elements - $this->lastLangs = $userLangs; // Store it for last use if not in req mode - return $userLangs; - } - - private function getConfigClassName($langcode) { - $langcode = str_replace('-','_',$langcode); - return $this->fileNamespace . '\\' . $langcode; - } - - private function getLangList($reqLang = null) { - // Quick Return the last used language list - if ($this->lastLangs != null && $reqLang == null) { - return $this->lastLangs; - } + $userLangs = array_intersect( + array_unique($judged_langs), // remove duplicate elements + $this->allowedLangSet + ); - $userLangs = $this->getUserLangs($reqLang); - - // remove illegal userLangs - $userLangs2 = array(); - foreach ($userLangs as $key => $value) { - // only allow a-z, A-Z and 0-9 and _ and - - if (preg_match('/^[a-zA-Z0-9_-]*$/', $value) === 1 && in_array($value, $this->allowedLangSet)) { - if (class_exists($this->getConfigClassName($value))) { - $userLangs2[] = $this->getConfigClassName($value); // change it to class name - } elseif ( - // Fail back if main language exist - $value !== substr($value, 0, 2) - && class_exists($this->getConfigClassName(substr($value, 0, 2)))) { - $userLangs2[] = $this->getConfigClassName(substr($value, 0, 2)); - } - } + foreach ($userLangs as $lang) { + $this->_user_lang = $lang; // Store it for last use if not in req mode + return $lang; } - - // remove duplicate elements - $userLangs2 = array_unique($userLangs2); - - // Cache the main languages list is not in request model - if ($reqLang == null) $this->lastLangs = $userLangs2; - return $userLangs2; + return null; } /** @@ -171,23 +156,18 @@ private function getLangList($reqLang = null) { * * @param string $string the trans string * @param array $args the args used for format string by using `vsprintf` - * @param string $lang the required lang + * @param string|null $domain The domain for the message or null to use the default + * @param string|null $required_lang the required lang * @return string */ - public function trans($string, $args = null, $lang = null) + public function trans($string, $args = [], $domain = null, $required_lang = null) { - $langs = $this->getLangList($lang); - - $return = ''; - foreach ($langs as $item) { - try { - $return = constant($item . "::" . $string); - break; - } catch (\Exception $e) { - app()->log->warning('A no-exist translation hit.', ['lang_class' => $item, 'string' => $string]); - } - } - return $args ? vsprintf($return, $args) : $return; + $local = + $this->forcedLang ?? // Highest priority: forced language + $required_lang ?? // 1st highest priority: required language + $this->getUserLang(); + + return $this->_translator->trans($string, $args, $domain, $local); } } diff --git a/framework/functions.php b/framework/functions.php index 2fcd538..e1e87f5 100644 --- a/framework/functions.php +++ b/framework/functions.php @@ -29,9 +29,9 @@ function env($name = null, $default = '') } if (!function_exists('__')) { - function __($string, $avg = null, $lang = null) + function __($string, $avg = [], $domain = null, $lang = null) { - return app()->i18n->trans($string, $avg, $lang); + return app()->i18n->trans($string, $avg, $domain, $lang); } } diff --git a/templates/index.php b/templates/index.php index 1b0eebd..f5fa497 100644 --- a/templates/index.php +++ b/templates/index.php @@ -89,7 +89,7 @@
-

Navbar

+

Navbar

I'm sorry for broken page since I'm building now and this work is not finishing.

stop() ?> diff --git a/templates/layout/nav_user.php b/templates/layout/nav_user.php index 8c4c004..f9d33b6 100644 --- a/templates/layout/nav_user.php +++ b/templates/layout/nav_user.php @@ -16,22 +16,22 @@