diff --git a/src/mibew/install/dbinfo.php b/src/mibew/install/dbinfo.php index 59d8cb0f..8e71aeb3 100644 --- a/src/mibew/install/dbinfo.php +++ b/src/mibew/install/dbinfo.php @@ -125,6 +125,16 @@ $dbtables = array( "translation" => "text", ), + // Contains locales info + "${mysqlprefix}locale" => array( + // Artificial primary key + "localeid" => "int NOT NULL auto_increment PRIMARY KEY", + // Locale code + "code" => "varchar(5) NOT NULL", + // Indicates if a locale is enabled or not. + "enabled" => "tinyint NOT NULL DEFAULT 0", + ), + // Contains localized mail templates "${mysqlprefix}mailtemplate" => array( // Artificial primary key diff --git a/src/mibew/install/index.php b/src/mibew/install/index.php index 4ff3b475..533ec5dc 100644 --- a/src/mibew/install/index.php +++ b/src/mibew/install/index.php @@ -402,6 +402,27 @@ function add_mail_templates($link){ } } +function add_locales($link) +{ + global $mysqlprefix; + + $localesresult = mysql_query("select code from ${mysqlprefix}locale", $link); + $existlocales = array(); + for ($i = 0; $i < mysql_num_rows($localesresult); $i++) { + $existlocales[] = mysql_result($localesresult, $i, 'code'); + } + $locales = discover_locales(); + foreach ($locales as $locale) { + if (in_array($locale, $existlocales)) { + // Do not add locales twice. + continue; + } + $query = "insert into ${mysqlprefix}locale (code, enabled) values ('" + . mysql_real_escape_string($locale, $link) . "', 1)"; + mysql_query($query, $link); + } +} + function get_yml_file_content($file) { $yaml = new \Symfony\Component\Yaml\Parser(); @@ -443,6 +464,7 @@ function check_status() return; } + add_locales($link); add_canned_messages($link); add_mail_templates($link); diff --git a/src/mibew/libs/classes/Mibew/Controller/Localization/AbstractController.php b/src/mibew/libs/classes/Mibew/Controller/Localization/AbstractController.php new file mode 100644 index 00000000..f2e1f386 --- /dev/null +++ b/src/mibew/libs/classes/Mibew/Controller/Localization/AbstractController.php @@ -0,0 +1,50 @@ +attributes->get('_route'); + + $tabs[getlocal('page_localization.tab.translation')] = ($route != 'translations') + ? $this->generateUrl('translations') + : ''; + + $tabs[getlocal('page_localization.tab.locale')] = ($route != 'locales') + ? $this->generateUrl('locales') + : ''; + + return $tabs; + } +} diff --git a/src/mibew/libs/classes/Mibew/Controller/Localization/LocaleController.php b/src/mibew/libs/classes/Mibew/Controller/Localization/LocaleController.php new file mode 100644 index 00000000..1381af62 --- /dev/null +++ b/src/mibew/libs/classes/Mibew/Controller/Localization/LocaleController.php @@ -0,0 +1,134 @@ +getOperator(); + $page = array( + // Use errors list stored in the request. We need to do so to have + // an ability to pass the request from other actions. + 'errors' => $request->attributes->get('errors', array()), + ); + + $fs_locales = discover_locales(); + $locale_names = get_locale_names(); + $available_locales = get_available_locales(); + + $locales_list = array(); + foreach($fs_locales as $locale) { + $locales_list[] = array( + 'code' => $locale, + 'name' => (isset($locale_names[$locale]) ? $locale_names[$locale] : $locale), + 'isDisabled' => !in_array($locale, $available_locales), + ); + } + + $page['localesList'] = $locales_list; + $page['title'] = getlocal('page_locales.title'); + $page['menuid'] = 'translation'; + $page = array_merge($page, prepare_menu($operator)); + $page['tabs'] = $this->buildTabs($request); + + return $this->render('locales', $page); + } + + /** + * Enables a locale. + * + * @param Request $request Incoming request. + * @return \Symfony\Component\HttpFoundation\Response A response object. + * @throws NotFoundException If the locale which should be enabled is not + * found. + */ + public function enableAction(Request $request) + { + csrf_check_token($request); + + $locale = $request->attributes->get('locale'); + + // Check if locale exists. + if (!in_array($locale, discover_locales())) { + throw new NotFoundException(); + } + + // Enable locale if it is needed and redirect the operator to the + // locales page. + if (!in_array($locale, get_available_locales())) { + enable_locale($locale); + } + + return $this->redirect($this->generateUrl('locales')); + } + + /** + * Disables a locale. + * + * @param Request $request Incoming request. + * @return \Symfony\Component\HttpFoundation\Response A response object. + * @throws NotFoundException If the locale which should be disabled is not + * found. + */ + public function disableAction(Request $request) + { + csrf_check_token($request); + + $locale = $request->attributes->get('locale'); + $errors = array(); + + // Check if locale exists. + if (!in_array($locale, discover_locales())) { + throw new NotFoundException(); + } + + // Disable locale if we can do so. + $available_locales = get_available_locales(); + if (in_array($locale, $available_locales)) { + if (count($available_locales) > 1) { + disable_locale($locale); + } else { + $errors[] = getlocal('page_locales.cannot_disable_all'); + } + } + + if (count($errors) != 0) { + // Something went wrong. Re-render locales list. + $request->attributes->set('errors', $errors); + + return $this->indexAction($request); + } + + return $this->redirect($this->generateUrl('locales')); + } +} diff --git a/src/mibew/libs/classes/Mibew/Controller/TranslationController.php b/src/mibew/libs/classes/Mibew/Controller/Localization/TranslationController.php similarity index 98% rename from src/mibew/libs/classes/Mibew/Controller/TranslationController.php rename to src/mibew/libs/classes/Mibew/Controller/Localization/TranslationController.php index 39c309f0..73a4df50 100644 --- a/src/mibew/libs/classes/Mibew/Controller/TranslationController.php +++ b/src/mibew/libs/classes/Mibew/Controller/Localization/TranslationController.php @@ -15,7 +15,7 @@ * limitations under the License. */ -namespace Mibew\Controller; +namespace Mibew\Controller\Localization; use Symfony\Component\HttpFoundation\Request; @@ -115,6 +115,7 @@ class TranslationController extends AbstractController $page['title'] = getlocal('page.translate.title'); $page['menuid'] = 'translation'; $page = array_merge($page, prepare_menu($operator)); + $page['tabs'] = $this->buildTabs($request); return $this->render('translations', $page); } diff --git a/src/mibew/libs/common/locale.php b/src/mibew/libs/common/locale.php index 2d4d0b91..85267998 100644 --- a/src/mibew/libs/common/locale.php +++ b/src/mibew/libs/common/locale.php @@ -63,17 +63,51 @@ function locale_pattern_check($locale) function get_available_locales() { - $list = array(); - $folder = MIBEW_FS_ROOT . '/locales'; - if ($handle = opendir($folder)) { - while (false !== ($file = readdir($handle))) { - if (locale_pattern_check($file) && is_dir("$folder/$file")) { - $list[] = $file; - } - } - closedir($handle); + if (installation_in_progress()) { + // We cannot get info from database during installation, thus we only + // can use discovered locales as available locales. + // TODO: Remove this workaround after installation will be rewritten. + return discover_locales(); + } + + // Get list of enabled locales from the database. + $rows = Database::getInstance()->query( + "SELECT code FROM {locale} WHERE enabled = 1", + array(), + array('return_rows' => Database::RETURN_ALL_ROWS) + ); + $enabled_locales = array(); + foreach ($rows as $row) { + $enabled_locales[] = $row['code']; + } + + $fs_locales = discover_locales(); + + return array_intersect($fs_locales, $enabled_locales); +} + +/** + * Returns list of all locales that are present in the file system. + * + * @return array List of locales codes. + */ +function discover_locales() +{ + static $list = null; + + if (is_null($list)) { + $list = array(); + $folder = MIBEW_FS_ROOT . '/locales'; + if ($handle = opendir($folder)) { + while (false !== ($file = readdir($handle))) { + if (locale_pattern_check($file) && is_dir("$folder/$file")) { + $list[] = $file; + } + } + closedir($handle); + } + sort($list); } - sort($list); return $list; } @@ -836,3 +870,59 @@ function save_message($locale, $key, $value) ); } } + +/** + * Enables specified locale. + * + * @param string $locale Locale code according to RFC 5646. + */ +function enable_locale($locale) +{ + $db = Database::getInstance(); + + // Check if the locale exists in the database + list($count) = $db->query( + "SELECT COUNT(*) FROM {locale} WHERE code = :code", + array(':code' => $locale), + array( + 'return_rows' => Database::RETURN_ONE_ROW, + 'fetch_type' => Database::FETCH_NUM, + ) + ); + + if ($count == 0) { + // The locale does not exist in the database. Create it. + $db->query( + "INSERT INTO {locale} (code, enabled) VALUES (:code, :enabled)", + array( + ':code' => $locale, + ':enabled' => 1, + ) + ); + } else { + // The locale exists in the database. Update it. + $db->query( + "UPDATE {locale} SET enabled = :enabled WHERE code = :code", + array( + ':enabled' => 1, + ':code' => $locale, + ) + ); + } +} + +/** + * Disables specified locale. + * + * @param string $locale Locale code according to RFC 5646. + */ +function disable_locale($locale) +{ + Database::getInstance()->query( + "UPDATE {locale} SET enabled = :enabled WHERE code = :code", + array( + ':enabled' => 0, + ':code' => $locale, + ) + ); +} diff --git a/src/mibew/libs/routing.yml b/src/mibew/libs/routing.yml index 6dc0f3ee..b81f0d80 100644 --- a/src/mibew/libs/routing.yml +++ b/src/mibew/libs/routing.yml @@ -323,6 +323,32 @@ invite: _controller: Mibew\Controller\InvitationController::inviteAction _access_check: Mibew\AccessControl\Check\LoggedInCheck +## Locales +locale_disable: + path: /operator/locale/{locale}/disable + defaults: + _controller: Mibew\Controller\Localization\LocaleController::disableAction + _access_check: Mibew\AccessControl\Check\PermissionsCheck + _access_permissions: [CAN_ADMINISTRATE] + requirements: + locale: "[a-z\-]{2,5}" + +locale_enable: + path: /operator/locale/{locale}/enable + defaults: + _controller: Mibew\Controller\Localization\LocaleController::enableAction + _access_check: Mibew\AccessControl\Check\PermissionsCheck + _access_permissions: [CAN_ADMINISTRATE] + requirements: + locale: "[a-z\-]{2,5}" + +locales: + path: /operator/locale + defaults: + _controller: Mibew\Controller\Localization\LocaleController::indexAction + _access_check: Mibew\AccessControl\Check\PermissionsCheck + _access_permissions: [CAN_ADMINISTRATE] + ## Log in login: path: /operator/login @@ -588,7 +614,7 @@ style_preview: translation_edit: path: /operator/translation/{string_id}/edit defaults: - _controller: Mibew\Controller\TranslationController::showEditFormAction + _controller: Mibew\Controller\Localization\TranslationController::showEditFormAction _access_check: Mibew\AccessControl\Check\PermissionsCheck _access_permissions: [CAN_ADMINISTRATE] requirements: @@ -598,7 +624,7 @@ translation_edit: translation_edit_save: path: /operator/translation/{string_id}/edit defaults: - _controller: Mibew\Controller\TranslationController::submitEditFormAction + _controller: Mibew\Controller\Localization\TranslationController::submitEditFormAction _access_check: Mibew\AccessControl\Check\PermissionsCheck _access_permissions: [CAN_ADMINISTRATE] requirements: @@ -608,7 +634,7 @@ translation_edit_save: translations: path: /operator/translation defaults: - _controller: Mibew\Controller\TranslationController::indexAction + _controller: Mibew\Controller\Localization\TranslationController::indexAction _access_check: Mibew\AccessControl\Check\PermissionsCheck _access_permissions: [CAN_ADMINISTRATE] diff --git a/src/mibew/locales/en/translation.po b/src/mibew/locales/en/translation.po index f9f08ceb..4cea7308 100644 --- a/src/mibew/locales/en/translation.po +++ b/src/mibew/locales/en/translation.po @@ -679,7 +679,7 @@ msgstr "Your translation is saved." msgid "page.translate.one" msgstr "Enter your translation." msgid "page.translate.title" -msgstr "Localization wizard" +msgstr "Translations" msgid "page_agent.cannot_modify" msgstr "You are not allowed to change this person's profile." msgid "page_agent.clear_avatar" @@ -790,6 +790,26 @@ msgid "page_group.tab.main" msgstr "General" msgid "page_group.tab.members" msgstr "Members" +msgid "page_locales.actions" +msgstr "Modify" +msgid "page_locales.cannot_disable_all" +msgstr "You cannot disable all locales." +msgid "page_locales.code" +msgstr "Code" +msgid "page_locales.disable.locale" +msgstr "disable" +msgid "page_locales.enable.locale" +msgstr "enable" +msgid "page_locales.intro" +msgstr "On this page you can configure locales which are used in the system" +msgid "page_locales.name" +msgstr "Name" +msgid "page_locales.title" +msgstr "Locales" +msgid "page_localization.tab.locale" +msgstr "Locales" +msgid "page_localization.tab.translation" +msgstr "Translations" msgid "page_login.error" msgstr "Entered login/password is incorrect" msgid "page_login.operator.disabled" diff --git a/src/mibew/styles/pages/default/templates_src/server_side/locales.handlebars b/src/mibew/styles/pages/default/templates_src/server_side/locales.handlebars new file mode 100644 index 00000000..35068c1d --- /dev/null +++ b/src/mibew/styles/pages/default/templates_src/server_side/locales.handlebars @@ -0,0 +1,64 @@ +{{#extends "_layout"}} + {{#override "menu"}}{{> _menu}}{{/override}} + + {{#override "content"}} + {{l10n "page_locales.intro"}} + +
+
+ + {{> _errors}} + + {{> _tabs}} + +
+
+
+
+ +
+ {{! It is just an empty plate under the tabs bar.}} + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + + + {{#each localesList}} + + + + + + + + {{/each}} + +
{{l10n "page_locales.code"}}{{l10n "page_locales.name"}}{{l10n "page_locales.actions"}}
+ {{code}} + + {{name}} + + {{#if isDisabled}} + {{l10n "page_locales.enable.locale"}} + {{else}} + {{l10n "page_locales.disable.locale"}} + {{/if}} +
+ {{/override}} +{{/extends}} \ No newline at end of file diff --git a/src/mibew/styles/pages/default/templates_src/server_side/translations.handlebars b/src/mibew/styles/pages/default/templates_src/server_side/translations.handlebars index 9e6f2c6e..da1025b8 100644 --- a/src/mibew/styles/pages/default/templates_src/server_side/translations.handlebars +++ b/src/mibew/styles/pages/default/templates_src/server_side/translations.handlebars @@ -8,6 +8,7 @@
+ {{> _tabs}}