fsi/translatable

处理翻译的库

1.1.0 2024-08-01 12:04 UTC

This package is auto-updated.

Last update: 2024-09-01 12:55:20 UTC


README

该组件旨在为多种语言提供创建可翻译对象的方法。该理念主要有两个概念 - 可翻译和翻译。可翻译的对象其数据存储在一个翻译对象集合中,每个对象对应一个单独的区域。每个这些都有一个独立的配置对象,其中存储了所有必要的信息,这些信息描述了两者之间的关系。这些是TranslatableConfigurationTranslationConfiguration,可以通过ConfigurationResolver检索。

可翻译对象的生存周期由Entity目录中的一些专用类处理,这些类是TranslationLoaderTranslationUpdaterTranslationCleaner。它们将

  • 设置可翻译对象的当前区域设置
  • 从翻译中加载数据(如果存在的话)
  • 创建新的翻译或更新现有的翻译
  • 删除空的翻译对象

但是,它们不能单独工作,需要通过订阅者连接到您正在使用的任何存储机制(ORM、ODM等)。目前,只有Doctrine / Symfony组合提供了开箱即用的集成。

哪些字段可以是可翻译字段?

当涉及到存储时,所有以下内容的映射/配置都应该包含在翻译实体文件中,而不是可翻译。

默认情况下

  • 标量值(字符串、整数、浮点数),
  • 对象(尽管它们的存储可能需要通过某些集成来处理),
  • WebFile对象从fsi/files组件将工作并持久化/删除与翻译实体一起,

与Doctrine一起

  • 嵌入式(嵌套),尽管嵌入式本身不能有翻译,因为没有标识符,
  • 一对一关系,
  • 集合关系,

示例实体

让我们考虑一个具有ArticleTranslation翻译的可翻译Article实体的例子

declare(strict_types=1);

namespace Tests\Entity;

use DateTimeImmutable;
use FSi\Component\Translatable\Integration\Doctrine\ORM\ProxyTrait;

class Article
{
    use ProxyTrait;

    private ?int $id = null;
    private ?string $locale = null;
    private ?DateTimeImmutable $publicationDate = null;
    private ?string $title = null;
    private ?string $description = null;

    // getters and setters will probably be required for whatever
    // mechanism you use for modifying the object, though are not
    // required by the component itself
}

declare(strict_types=1);

namespace Tests\Entity;

class ArticleTranslation
{
    private ?int $id = null;
    private ?string $locale = null;
    private ?string $title = null;
    private ?string $description = null;
    private ?Article $article;

    // getters and setters are not required
}

如你所见,它们几乎是一致的,除了可翻译中的$publicationDate字段和翻译中的$article字段。这是因为$publicationDate不是可翻译字段(它直接存储在可翻译对象中),而$article作为将翻译绑定到可翻译对象的方式。这两个字段都有locale字段:可翻译存储当前区域,翻译存储创建时的区域。

为了使组件能够识别这些对象作为可翻译-翻译对,您需要定义它们的配置。当使用Symfony时,这可以像这样简单地完成

fsi_translatable:
    entities:
        Tests\Entity\Article:
            localeField: locale # this can be skipped for a default value of locale
            fields: [title, description]
            disabledAutoTranslationsUpdate: false # optional and false by default
            translation:
                localeField: locale # also can be skipped
                class: Tests\FSi\ArticleTranslation
                relationField: article

重要

  • 两个对象都需要有相同的字段。不可能将可翻译字段映射到翻译实体中的不同字段。
  • 翻译对象不能有必需的构造函数参数。

如果您想手动创建配置,您需要向ConfigurationResolver提供一个包含必要数据的TranslatableConfiguration对象的集合。

用法(Doctrine + Symfony)

除非您直接在Kernel类中加载您的束和配置,否则您需要在config/bundles.php中加载Translatable束

return [
    // Doctrine and Symfony bundles
    FSi\Component\Translatable\Integration\Symfony\TranslatableBundle::class => ['all' => true]
];

然后添加一个config/packages/fsi_translatable.yaml文件

fsi_translatable:
    entities:
        # configuration for specific entities, see above for an example

当然,您可以通过PHP手动加载配置,但目前不支持XML配置。

之后,组件将主要自动运行。当创建一个新的可翻译对象,并且任何一个可翻译字段被填写时,将通过 LocaleProvider 对象获取当前区域设置,创建一个新的翻译实例,然后将可翻译对象的相关内容复制到其中。在随后的可翻译对象加载过程中,数据将从存储的翻译中重新加载。对可翻译对象中可翻译字段的任何修改将自动更新现有翻译。如果 LocaleProvider 提供的区域设置不同,将创建一个新的翻译。

如果出于某种原因您需要直接获取单个/所有翻译对象,可以通过 TranslationProvider 来实现。

如果移除了一个可翻译对象,将通过 Doctrine 的实体管理器(通过 TranslationManager)清除所有翻译,因此任何监听翻译实体生命周期事件的订阅者也将被触发。

重要

  • 如果您有可翻译的集合字段,您必须在翻译对象构造函数中 初始化 它们。

区域设置获取和持久化

Symfony 的 LocaleProvider 实现将尝试从三个来源获取区域设置

  1. 它将检查持久化的区域设置(关于这一点稍后详细说明)。
  2. 如果找不到,它将从 RequestStack 中获取一个当前的 Request 对象,并从该对象中检索区域设置。
  3. 如果没有当前的 Request(这对于控制台命令和一些测试环境将是这种情况),它将返回 FrameworkBundle 中的默认区域设置。

如果您想手动设置从 LocaleProvider 返回的区域设置,调用 LocaleProvider::saveLocale() 方法将将其持久化到服务中,直到下一次请求。您也可以手动调用 LocaleProvider::resetSavedLocale() 来清除它。

禁用自动翻译更新

如果您更喜欢手动创建翻译,并且不想让它们被可翻译实体的内容覆盖,可以在其配置中将 disableAutoTranslationsUpdate 选项设置为 true。这将防止在刷新操作期间创建或更新翻译,但仍然会在当前区域设置存在翻译实体的情况下,将翻译实体的内容填充到可翻译实体中。