diff --git a/apps/config/http_base.php b/apps/config/http_base.php index 27f2ee6..5a95677 100644 --- a/apps/config/http_base.php +++ b/apps/config/http_base.php @@ -191,7 +191,16 @@ 'user' => [ 'class' => Rid\User\User::class, - ] + ], + + 'i18n' => [ + 'class' => Rid\I18n\I18n::class, + 'fileNamespace' => 'apps\lang', + 'fallbackLang' => 'en', + 'mergeFallback' => true, + 'forcedLang' => null, + 'allowedLangSet' => ['en', 'zh-CN'] + ], ], // 类库配置 diff --git a/apps/lang/en.php b/apps/lang/en.php new file mode 100644 index 0000000..89d3907 --- /dev/null +++ b/apps/lang/en.php @@ -0,0 +1,15 @@ + -layout('layout/base') ?> +layout('layout/base') ?> + +start('title')?>Indexend();?> start('container') ?>
-

Navbar example

-

I'm sorry for broken page since I'm rebuilding.

+

Navbar

+

I'm sorry for broken page since I'm rebuilding.

stop() ?> diff --git a/framework/Base/Application.php b/framework/Base/Application.php index 57fbd6c..7003c27 100644 --- a/framework/Base/Application.php +++ b/framework/Base/Application.php @@ -17,6 +17,7 @@ * @property \Rid\Config\DynamicConfig $config * @property \Rid\Pool\ConnectionPool $connectionPool * @property \Rid\User\User $user + * @property \Rid\I18n\I18n $i18n */ class Application extends BaseObject { @@ -36,7 +37,7 @@ class Application extends BaseObject // 初始化事件 public function onInitialize() { - parent::onInitialize(); // TODO: Change the autogenerated stub + parent::onInitialize(); // 快捷引用 \Rid::setApp($this); // 错误注册 diff --git a/framework/I18n/I18n.php b/framework/I18n/I18n.php new file mode 100644 index 0000000..01599b0 --- /dev/null +++ b/framework/I18n/I18n.php @@ -0,0 +1,183 @@ +lastLang != null && $reqLang == null) { + return $this->lastLang; + } + + // Highest priority: forced language + if ($this->forcedLang != NULL) $userLangs[] = $this->forcedLang; + + // 1st highest priority: required language + if ($reqLang != null) { + $userLangs[] = $reqLang; + } else { + // 2nd highest priority: GET parameter 'lang' + if (!is_null(app()->request->get('lang'))) $userLangs[] = app()->request->get('lang'); + + // 3rd highest priority: SESSION parameter 'lang' + if (!is_null(app()->user->getLang())) $userLangs[] = app()->user->getLang(); + + // 4th 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,ru;q=0.4' (length=32) + * And then sort to an array like this + * + * array(size=4) + * 'en-US' => float 1 + * 'en' => float 0.8 + * 'uk' => float 0.6 + * 'ru' => float 0.4 + * + */ + $prefLocales = array_reduce( + explode(',', app()->request->header('accept_language')), + function ($res, $el) { + list($l, $q) = array_merge(explode(';q=', $el), [1]); + $res[$l] = (float)$q; + return $res; + }, []); + arsort($prefLocales); + + foreach ($prefLocales as $part => $q) { + $userLangs[] = $part; + } + } + } + + // Lowest priority: fallback + $userLangs[] = $this->fallbackLang; + + $userLangs = array_unique($userLangs); // remove duplicate elements + $this->lastLang = $userLangs; // Store it for last use. + return $userLangs; + } + + protected function getConfigClassName($langcode) { + $langcode = str_replace('-','_',$langcode); + return $this->fileNamespace . '\\' . $langcode; + } + + private function getLangList($lang = null) { + $userLangs = $this->getUserLangs($lang); + + // 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)); + } + } + } + + // remove duplicate elements + return array_unique($userLangs2); + } + + + public function trans($string, $args = null, $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; + } +} diff --git a/framework/User/UserTrait.php b/framework/User/UserTrait.php index 42d8a11..1acd3c3 100644 --- a/framework/User/UserTrait.php +++ b/framework/User/UserTrait.php @@ -25,6 +25,8 @@ trait UserTrait private $avatar; + private $lang; + private $create_at; private $last_login_at; private $last_access_at; @@ -287,4 +289,12 @@ public function getActiveLeech() } return $active_leech; } + + /** + * @return mixed + */ + public function getLang() + { + return $this->lang; + } } diff --git a/framework/functions.php b/framework/functions.php index da266cc..ba5a1ef 100644 --- a/framework/functions.php +++ b/framework/functions.php @@ -27,6 +27,13 @@ function env($name = null, $default = '') } } +if (!function_exists('__')) { + function __($string, $avg = null, $lang = null) + { + return app()->i18n->trans($string, $avg, $lang); + } +} + if (!function_exists('tgo')) { /** 创建一个带异常捕获的协程 diff --git a/migration/ridpt.sql b/migration/ridpt.sql index 6d1ae11..67cb3ab 100644 --- a/migration/ridpt.sql +++ b/migration/ridpt.sql @@ -3,7 +3,7 @@ -- https://www.phpmyadmin.net/ -- -- Host: 127.0.0.1 --- Generation Time: Mar 08, 2019 at 08:30 AM +-- Generation Time: Mar 13, 2019 at 03:26 PM -- Server version: 8.0.14 -- PHP Version: 7.3.1 @@ -598,6 +598,7 @@ CREATE TABLE IF NOT EXISTS `users` ( `bonus_seeding` decimal(20,2) UNSIGNED NOT NULL DEFAULT '0.00', `bonus_invite` decimal(20,2) UNSIGNED NOT NULL DEFAULT '0.00', `bonus_other` decimal(20,2) UNSIGNED NOT NULL DEFAULT '0.00', + `lang` varchar(10) NOT NULL DEFAULT 'en', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`), UNIQUE KEY `email` (`email`),