terminal42/dc_multilingual

一个多语言DC驱动,用于Contao开源CMS,将翻译存储在同一张表中

资助包维护!
terminal42
其他

安装次数: 70,090

依赖: 10

建议者: 3

安全: 0

星标: 17

关注者: 9

分支: 8

开放性问题: 4

类型:contao-bundle

4.5.4 2024-07-08 09:19 UTC

README

这是一个独立的DC驱动,用于Contao开源CMS,允许您轻松地使数据可翻译。

DCA配置

// Set the driver
$GLOBALS['TL_DCA']['table']['config']['dataContainer'] = \Terminal42\DcMultilingualBundle\Driver::class;

// Languages you want to provide for translation (default: Languages of all root pages)
$GLOBALS['TL_DCA']['table']['config']['languages'] = ['en', 'de', 'pl'];

// Database column that contains the language keys (default: "language")
$GLOBALS['TL_DCA']['table']['config']['langColumnName'] = 'language';

// Database column that contains the reference id (default: "langPid")
$GLOBALS['TL_DCA']['table']['config']['langPid'] = 'langPid';

// Fallback language - if none is given then there will be another language "fallback" selectable from the dropdown
$GLOBALS['TL_DCA']['table']['config']['fallbackLang'] = 'en';

// Use '*' to make a field translatable for all languages
$GLOBALS['TL_DCA']['table']['fields']['username']['eval']['translatableFor'] = '*';

// Use an array of language keys to specify for which languages the field is translatable
$GLOBALS['TL_DCA']['table']['fields']['name']['eval']['translatableFor'] = ['de'];

// Note:
// If you don't use ['eval']['translatableFor'] and the user is not editing the fallback language, then the field will be hidden for all the languages

示例用法

// Update tl_news configuration
$GLOBALS['TL_DCA']['tl_news']['config']['dataContainer'] = \Terminal42\DcMultilingualBundle\Driver::class;
$GLOBALS['TL_DCA']['tl_news']['config']['languages'] = ['en', 'de', 'pl'];
$GLOBALS['TL_DCA']['tl_news']['config']['langPid'] = 'langPid';
$GLOBALS['TL_DCA']['tl_news']['config']['langColumnName'] = 'language';
$GLOBALS['TL_DCA']['tl_news']['config']['fallbackLang'] = 'en';

// Add the language fields
$GLOBALS['TL_DCA']['tl_news']['config']['sql']['keys']['langPid'] = 'index';
$GLOBALS['TL_DCA']['tl_news']['config']['sql']['keys']['language'] = 'index';
$GLOBALS['TL_DCA']['tl_news']['fields']['langPid']['sql'] = "int(10) unsigned NOT NULL default '0'";
$GLOBALS['TL_DCA']['tl_news']['fields']['language']['sql'] = "varchar(2) NOT NULL default ''";

// Make some fields translatable
$GLOBALS['TL_DCA']['tl_news']['fields']['headline']['eval']['translatableFor'] = '*';
$GLOBALS['TL_DCA']['tl_news']['fields']['subheadline']['eval']['translatableFor'] = ['de'];

使用模型进行查询

class NewsModel extends Terminal42\DcMultilingualBundle\Model\Multilingual
{
    protected static $strTable = 'tl_news';

    public static function findPublished()
    {
        return static::findBy(['t1.published=?'], [1]);
    }
}

内部工作原理

基本上,驱动器只将翻译存储到同一张表中,使用“langPid”列(或您配置的任何列)建立与其父条目的关系。在后台列表和树视图中,它确保翻译被过滤,以便您只能在那里看到后备语言。当使用Multilingual模型或使用MultilingualQueryBuilder进行查询时,简单地将相同的表连接起来,这样我们就有后备语言别名为t1和目标语言(您明确指定的或使用当前页面的语言)别名为translation。现在,使用MySQL的IFNULL()函数,它会检查是否存在翻译值,如果没有,则自动回退到后备语言。这允许您仅翻译字段的一部分。

别名处理

您可以将所有翻译的别名共享,因此您会得到类似这样的结果

* EN: domain.com/my-post/my-beautiful-alias.html
* DE: domain.de/mein-artikel/my-beautiful-alias.html
* FR: domain.fr/mon-post/my-beautiful-alias.html

这可以通过使用您可能从其他模块(如新闻等)在后台了解的常规别名处理来实现。对于前端,您只需使用Multilingual模型提供的findByAlias()方法即可

MyModel::findByAlias($alias);

然而,有许多情况下,您可能希望将别名翻译成这样

* EN: domain.com/my-post/my-beautiful-alias.html
* DE: domain.de/mein-artikel/mein-wunderschoenes-alias.html
* FR: domain.fr/mon-post/mon-alias-magnifique.html

在后台,这稍微困难一些,因为现在没有检查整个表中是否有重复别名的意义,但只有在相同语言的全表中才有意义。为了尽可能方便您,只需在您的alias字段上使用以下eval定义即可

'eval'      => [
    'maxlength'                 => 255,
    'rgxp'                      => 'alias',
    'translatableFor'           => '*',
    'isMultilingualAlias'       => true,
    'generateAliasFromField'    => 'title' // optional ("title" is default)
],

它将自动生成别名(如果尚未存在),并在相同语言内检查重复项。

然后您可以在前端通过多语言别名进行搜索

MyModel::findByMultilingualAlias($alias);

与Doctrine实体一起使用

由于驱动器只从后台将数据写入数据库,因此它与前端使用Doctrine实体完全兼容。目前,您必须自己处理翻译。以下是一个实体的示例

#[Entity()]
#[Table('tl_my_entity')]
class MyEntity
{
    #[Id]
    #[GeneratedValue('IDENTITY')]
    #[Column(options: ['unsigned' => true])]
    private int $id;
    #[Column(options: ['unsigned' => true, 'default' => 0])]
    private int $tstamp;

    #[OneToMany('parent', self::class)]
    protected $translations;
    #[ManyToOne(self::class, inversedBy: 'translations')]
    #[JoinColumn('langPid')]
    protected $parent;
    #[Column(length: 5, options: ['default' => ''])]
    protected string $language;

    // ... any other properties of your entity
}

有用的注意事项

  1. 有时,您想要使其多语言化的表已经包含language字段(例如tl_user),这可能会导致意外结果。在这种情况下,您必须确保数据容器的属性$GLOBALS['TL_DCA']['tl_table']['config']['langColumnName']设置为不是language的任何内容。有关更多详细信息,请参阅#53