分类目录归档:Phabricator

一个小问题Phabricator的部分界面无法本地化

最近我进行了一些Phabricator本地化的工作,在这个过程中,我发现Phabricator的一小部分界面始终无法翻译,即使我在PhabricatorCNChineseTranslation.php中添加了相应的翻译项。

这部分无法翻译的界面是下图中的”Tag”这样的文字。
"Tag"无法被翻译

Phabricator是通过pht函数实现本地化的,pht(‘User’)将会返回User的本地化翻译,如果没有可用的翻译,那么就会返回’User’自身。

如果我们深入Phabricator的代码,我们不难发现,上图中的”Tag”之所以无法翻译,是因为这个”Tag”来源于PhabricatorProjectIconSet类的如下代码。

private static function getIconSpecifications() {
  return PhabricatorEnv::getEnvConfig('projects.icons');
}

上述代码其实是从Phabricator的配置项projects.icons中载入”Tag”, “Project”等配置。
这个配置项其实就是一串JSON
projects.icons

不难看出,无论如何,载入projects.icons的时候,Phabricator不会对projects.icons这个配置项的内容进行任何pht操作,这也就导致”Tag”等文本不会被翻译了。

我在自己的本地代码中,对PhabricatorProjectIconSet进行了如下改动,即在getIconSpec和getIconName函数上加上pht的调用。这样就可以实现本地化翻译了。但是,这样的改动是不符合Phabricator的pht规范的,即传入给pht的参数必须是scala string value,而由于下面的代码的缘故,我们并不能保证pht($value)的$value是一个scala value,理论上也可能是一个array(projects.icons是一个可以任意修改的配置项,所以我们并不能保证$value是scala),所以,我的代码是不能通过arc lint的。

 public static function getIconName($key) {
    $spec = self::getIconSpec($key);
    return pht(idx($spec, 'name', null));
  }

 private static function getIconSpec($key) {
    $icons = self::getIconSpecifications();
    foreach ($icons as $icon) {
      if (idx($icon, 'key') === $key) {
        $spec_local = array();
        foreach ($icon as $key => $value) {
          if ($key == 'name') {
            $spec_local['name'] = pht($value);
          } else {
            $spec_local[$key] = $value;
          }
        }
        return $spec_local;
      }
    }

    return array();
  }

简而言之,上述的代码只是一个补丁,仍然不是最好的方案,但是至少能够保证翻译了。

让Phabricator支持中文的全文搜索

Phabricator是一款优秀的开源项目管理、代码评审和代码管理平台,然而,默认情况下,它对于中文搜索的支持存在问题。

例如,如果你新建了一个标题为“公司年会准备工作”的Maniphest Task,那么,你在Phabricator中用“公司”或者“年会”进行搜索,是搜不到“公司年会准备工作”。这是因为Phabricator默认安装的时候,使用的是MySQL的全文索引,而MySQL默认的分词器是按照空白字符进行分词的,因此,“公司年会准备工作”是作为一个词语进行索引,而不是按照“公司”“年会”“准备”“工作”四个词语进行索引。

解决的办法有不少,例如,我们可以使用ElasticSearch为Phabricator的搜索引擎。不过,其实MySQL的全文索引是支持中文分词的,从MySQL 5.7.6开始,MySQL增加了NGRAM分词器,当你设置ngram_token_size=2时,“公司年会”会被分词为“公司” “司年” “年会”。

Phabricator的MySQL全文索引建立在phabricator_search库的search_documentfield表上,索引名称为corpus,对应的表的列名为corpus。 索引名称为key_corpus,对应的列为corpus和stemmedCorpus。



CREATE TABLE `search_documentfield` (
`phid` varbinary(64) NOT NULL,
`phidType` varchar(4) COLLATE {$COLLATE_TEXT} NOT NULL,
`field` varchar(4) COLLATE {$COLLATE_TEXT} NOT NULL,
`auxPHID` varbinary(64) DEFAULT NULL,
`corpus` longtext CHARACTER SET {$CHARSET_FULLTEXT} COLLATE {$COLLATE_FULLTEXT},
KEY `phid` (`phid`),
FULLTEXT KEY `corpus` (`corpus`)
) ENGINE=MyISAM DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};

我们看到,DDL语句中,创建全文索引的部分为“FULLTEXT KEY `corpus` (`corpus`)”,这使用的是默认的MySQL分词器,如果我们要使用NGRAM分词器,这个语句应该写成“FULLTEXT KEY `corpus` (`corpus`) WITH PARSER NGRAM”。

我已经有了一个已经安装好的Phabricator实例,我并不想重新安装Phabricator,所以,我的做法是删除掉corpus索引,然后重新建立以NGRAM作为分词器的corpus索引。

SQL语句如下(之前的版本)

USE phabricator_search;
DROP INDEX `corpus` ON `search_documentfield`;
CREATE FULLTEXT INDEX `corpus` ON `search_documentfield`(`corpus`) WITH PARSER NGRAM;

SQL语句如下(最新的版本)

USE phabricator_search;
DROP INDEX `key_corpus` ON `search_documentfield`;
CREATE FULLTEXT INDEX `key_corpus` ON `search_documentfield`(`corpus`,`stemmedCorpus`) WITH PARSER NGRAM;

我设置MySQL的ngram_token_size为2,因为中文中两个字的词非常多。

我的my.cnf中添加了以下配置项

[mysqld]
ngram_token_size=2