We previously demonstrated the proper way to get started with Sulu CMS by setting up a Hello World installation on a Vagrant machine. Simple stuff, but can be tricky.

之前,我们通过在Vagrant机器上设置Hello World安装, 演示了开始使用Sulu CMS的正确方法。 简单的东西,但可能很棘手。

If you’re a stranger to Vagrant and isolated environments, our excellent book about that very thing is available for purchase.

如果您不熟悉Vagrant和孤立的环境, 可以购买有关该产品的出色书籍。

This time we’ll look into basic Sulu terminology, explain how content is formed, created, stored, and cached, and look into building a simple online magazine with different locales (languages).

这次,我们将研究基本的Sulu术语,解释内容的形成,创建,存储和缓存方式,并研究构建具有不同语言环境(语言)的简单在线杂志。



Recommended reading before you continue:

建议您在继续之前阅读:

  • Setting up Isolated Development Environments for PHP – 5 minute read

    为PHP设置隔离的开发环境 – 5分钟阅读

  • Getting started with Sulu on Vagrant the Right Way – 10 minute read

    苏鲁(Sulu)以正确的方式入门 -十分钟的阅读时间



页面和页面模板 (Pages and Page Templates)

A page is exactly what you’d expect it to be: a block of content, often composed of smaller blocks. A page template is a two-part recipe for how a page is assembled.

页面正是您所期望的:一个内容块,通常由较小的块组成。 页面模板是组成页面的两部分方法。

A page template has two parts: the twig template, and the XML configuration. The Twig part is responsible for rendering the content of the page’s sub-blocks, like so:

页面模板分为两部分: 树枝模板和XML配置。 Twig部分负责呈现页面子块的内容,如下所示:

{% extends "master.html.twig" %}
{% block meta %}
{% autoescape false %}
{{ sulu_seo(extension.seo, content, urls, shadowBaseLocale) }}
{% endautoescape %}
{% endblock %}
{% block content %}
<h1 property="title">{{ content.title }}</h1>
<div property="article">
{{ content.article|raw }}
</div>
{% endblock %}

This is the full content of the default twig template that comes with sulu-minimal, found at app/Resources/Views/Templates/default.html.twig. It extends a master layout, defines some blocks, and renders their content.

这是sulu-minimal附带的默认树枝模板的完整内容,可在app/Resources/Views/Templates/default.html.twig 。 它扩展了主布局,定义了一些块,并渲染了它们的内容。

The XML configuration on the other hand is a bit more convoluted (as most things with XML are):

另一方面,XML配置有些复杂(与XML的大多数情况一样):

...
<key>default</key>
<view>templates/default</view>
<controller>SuluWebsiteBundle:Default:index</controller>
<cacheLifetime>2400</cacheLifetime>
<meta>
<title lang="en">Default</title>
<title lang="de">Standard</title>
</meta>
<properties>
<section name="highlight">
<properties>
<property name="title" type="text_line" mandatory="true">
<meta>
<title lang="en">Title</title>
<title lang="de">Titel</title>
</meta>
<params>
<param name="headline" value="true"/>
</params>
<tag name="sulu.rlp.part"/>
</property>
...

If you’re new to Sulu, none of this will make sense yet – but we’ll get there. For now, we’re introducing concepts. The main takeaways from the above snippet of XML are:

如果您是Sulu的新手,那么这一切都没有道理-但是我们会到达那里。 目前,我们正在介绍概念。 上面的XML代码片段的主要收获是:

  • the key is the unique slug of the template, and its entry into the admin template selection menu (it must be identical to the filename of the xml file, without the extension).

    key是模板的唯一子段,并且它是进入管理模板选择菜单的条目(它必须与xml文件的文件名相同,没有扩展名)。

  • the view is where its twig counterpart can be found. A template will only appear in the menu if it has both the XML and corresponding Twig file!

    view是可以找到其对应twig地方。 如果模板同时具有XML和相应的Twig文件,则仅会出现在菜单中!

  • the controller is where its logic is executed. We’ll go into more detail on controllers later on, but in general you can leave this at its default value for simple content.控制器是执行其逻辑的地方。 稍后我们将详细介绍控制器,但是对于简单的内容,通常可以将其保留为默认值。
  • meta data is how the template will appear in the admin template selection menu, depending on the language selected in the UI:

    元数据是模板在管理模板选择菜单中的显示方式,具体取决于用户界面中选择的语言:

    meta data is how the template will appear in the admin template selection menu, depending on the language selected in the UI:

    元数据是模板在管理模板选择菜单中的显示方式,具体取决于用户界面中选择的语言:

  • properties are various elements of the page – in this case, a field to input a title and a non-editable URL field属性是页面的各种元素–在这种情况下,是一个用于输入标题的字段和一个不可编辑的URL字段

You define new page types (templates) by defining new combinations of properties in this XML file, and then rendering them out in the corresponding twig file.

您可以通过在此XML文件中定义属性的新组合,然后在相应的树枝文件中将它们呈现出来,来定义新的页面类型(模板)。

As an experiment, try using the menu in the admin interface to switch the Homepage to the Default template, then in the master.html.twig layout file (one folder above), add nonsense into the HTML. Feel free to also populate the article property in the UI.

作为实验,请尝试使用管理界面中的菜单将“主页”切换为“默认”模板,然后在master.html.twig布局文件(上方的一个文件夹)中,将废话添加到HTML中。 还可以在UI中填充article属性。

...
<form action="{{ path('sulu_search.website_search') }}" method="GET">
<input name="q" type="text" placeholder="Search" />
<input type="submit" value="Go" />
</form>
Lalala
<section id="content" vocab="http://schema.org/" typeof="Content">
{% block content %}{% endblock %}
</section>
...

If you click Save and Publish in the top left corner now and refresh the homepage, you should see the changes.

如果现在单击左上角的“ Save and Publish ”并刷新主页,则应该看到所做的更改。

For the curious: you may be wondering why they took the XML route instead of having users manage everything in the database. Reason one is being able to version-control these files. Reason two is that even if one were to add a property in a GUI, it would still be missing from the twig template. At that point, they would either have to make twig templates editable in the GUI via a DB too, or the user would again be forced to edit files – and if they’re already editing them, they may as well edit XML files.

出于好奇:您可能想知道为什么他们选择XML路由而不是让用户管理数据库中的所有内容。 原因之一是能够对这些文件进行版本控制。 原因二是,即使有人要在GUI中添加属性,树枝模板仍会丢失该属性。 那时,他们要么不得不通过DB在GUI中使树枝模板可编辑,要么再次迫使用户编辑文件-如果他们已经在编辑它们,他们还可以编辑XML文件。

页面与主题 (Pages vs Themes)

So what’s a theme in all this?

那么,所有这一切的主题是什么?

A theme is a collection of page types. Contrary to popular belief, a theme is not a master layout which is then extended by the page template twigs – it’s a whole collection of page templates and master layouts to use. A theme will also contain all the necessary assets to fully render a site: CSS, JS, images, fonts, and more.

主题是页面类型的集合。 与流行的看法相反,主题不是主布局,而是通过页面模板的细枝进行扩展–它是要使用的页面模板主布局的完整集合。 主题还将包含完全呈现网站的所有必要资产:CSS,JS,图像,字体等。

For the curious: We won’t be dealing with themes in this tutorial but feel free to read up on them here.

出于好奇:我们不会在本教程中处理主题,但是请随时在此处阅读主题。

关于缓存 (About Caching)

If the homepage content doesn’t change when you modify it and refresh, it might have something to do with cache. Here are important things to keep in mind:

如果在修改和刷新时首页内容未更改,则可能与缓存有关。 这里有一些重要的事情要牢记:

  • during development, your server setup should set Symfony development environment variables. This allows you to deploy the app directly to production without modifying the environment value manually in files like web/admin.php or web/website.php, and makes your app highly debuggable in development. The values are SYMFONY_ENV and SYMFONY_DEBUG, and are automatically set if you’re using Homestead Improved. If not, copy them over from here if you’re on Nginx.

    在开发期间,您的服务器设置应设置Symfony开发环境变量。 这使您可以直接将应用程序部署到生产环境中,而无需在诸如web/admin.phpweb/website.php类的文件中手动修改环境值,并使您的应用程序在开发中具有很高的可调试性。 值是SYMFONY_ENVSYMFONY_DEBUG ,如果您使用Homestead SYMFONY_DEBUG ,则会自动设置这些值。 如果不是,请在使用Nginx时从此处复制它们。

  • the command line of Symfony apps (so, when using bin/adminconsole or bin/websiteconsole in the project) defaults to the dev environment. In order to execute commands for another environment, pass the --env= flag with the environment to match, like so: bin/adminconsole cache:clear --env=prod. This might trip you up if your app is in prod mode and you’re trying to clear cache but nothing is happening – could be the environments don’t match, and the command is clearing the wrong cache.

    Symfony应用程序的命令行 (因此,在项目中使用bin/adminconsolebin/websiteconsole bin/adminconsole时)默认为dev环境。 为了在其他环境中执行命令,请将--env=标志与环境匹配,例如: bin/adminconsole cache:clear --env=prod 。 如果您的应用程序处于prod模式,并且您试图清除缓存,但没有任何React,这可能会使您绊倒–可能是环境不匹配,并且该命令正在清除错误的缓存。

在线杂志 (An Online Magazine)

Let’s consider wanting to launch an online magazine. By definition, such a magazine has:

让我们考虑要发行在线杂志。 根据定义,这样的杂志有:

  • pages that explain things, like “About”, “Contact”, “Careers”, etc.解释诸如“关于”,“联系”,“职业”等内容的页面。
  • many articles, often grouped by month (as evident by the common URL pattern: mysite.com/05/2017/some-title-goes-here)很多文章,通常按月份分组(常见的网址格式很明显:mysite.com/05/2017/some-title-goes-here)
  • different permissions for different staff member levels (author, editor, guest, admin…)不同工作人员级别(作者,编辑,来宾,管理员等)的权限不同
  • a media library in which to store static files for inclusion in posts and pages (images, CSS, JS, etc.)一个媒体库,用于存储静态文件以包含在帖子和页面中(图像,CSS,JS等)

These are all things Sulu supports, with a caveat. When building something like this, we need keep storage in Sulu in mind.

这些都是Sulu支持的所有事项,但请注意。 当构建这样的东西时,我们需要牢记存储在Sulu中。

aw (Jackawhat?)

This section might sound confusing. There’s no way to make it easier to understand. Be comforted by the fact that you don’t need to know anything about it at all, and treat it as “for those who want to know more” material.

这部分听起来可能令人困惑。 无法使它更容易理解。 您完全不需要了解任何事实,并将其视为“供那些想了解更多信息的人”的资料而感到欣慰。

Jackalope is a PHP implementation of PHPCR which is a version of JCR. The rabbit hole is very deep with these terms, so I recommend avoiding trying to learn more about them. If you insist, it’s somewhat covered in this gist.

鹿角兔是一个PHP实现PHPCR这是一个版本JCR 。 这些术语对兔子洞很深,因此我建议避免尝试进一步了解它们。 如果您坚持要点 ,则本要点已涵盖了该部分 。

In a nutshell, if you don’t need to version your content, you’re fine with the default Jackalope-Doctrine-DBAL package that Sulu pulls in automatically. It’ll store content in a usual RDBMS (e.g. MySQL) but without versions.

简而言之,如果您不需要对内容进行版本控制,则可以使用Sulu自动插入的默认Jackalope-Doctrine-DBAL软件包。 它将内容存储在普通的RDBMS(例如MySQL)中,但没有版本。

If you do need versioning, you need to install Jackrabbit – an Apache product that’s basically a database server with a non-obvious twist, and use a different PHP implementation to store the content: Jackalope-Jackrabbit (also pulled in automatically). Note that an RDBMS is still needed – Jackrabbit merely augments it by providing a different storage mechanism for the actual content, but permissions, settings, etc. are still stored in a regular database.

如果确实需要版本控制,则需要安装Jackrabbit(一种Apache产品,基本上是一种不明显的扭曲的数据库服务器),并使用不同PHP实现来存储内容:Jackalope-Jackrabbit(也自动引入)。 请注意,仍然需要RDBMS-Jackrabbit只是通过为实际内容提供不同的存储机制来增强它,但是权限,设置等仍存储在常规数据库中。

The catch is that Jackrabbit (and PHPCR in general) has a limit of 10000 children per node. Since articles on online magazines and blogs are usually sequential and don’t have a hierarchy (i.e. they’re flat), they would end up being children of “root”, and after 10k posts you’d be in trouble.

问题是Jackrabbit(通常是PHPCR)每个节点最多只能有10000个孩子。 由于在线杂志和博客上的文章通常是连续的,并且没有层次结构(即,它们是扁平的 ),因此它们最终将成为“ root”的子代,并且在发布10k帖子之后,您将遇到麻烦。

This is why the Sulu team have developed a bundle which will auto-shard content by month and emulate a flat structure. By setting each month as a parent, each month can have 10000 posts. If need be, this can be further fragmented by week, or even by day. Keep this in mind:

这就是Sulu团队开发了一个捆绑包的原因, 该捆绑包将按月自动分片内容并模拟平面结构。 通过将每个月设置为父母,每个月可以有10000个帖子。 如果需要,可以按周甚至按天进一步细分。 请记住以下几点:

The ArticleBundle is a prerequisite if you’re building a news site, blog site, or magazine because otherwise, after 10000 units of content, you’d be in trouble.

如果您要构建新闻网站,博客网站或杂志,那么ArticleBundle是先决条件 ,因为否则,在10000单位的内容之后,您会遇到麻烦。

Note: The ArticleBundle is currently under heavy development, and is likely to have some API changes before a 1.0 release. Use with caution.

注意:ArticleBundle目前正在大量开发中,并且可能会在1.0版本之前对API进行一些更改。 请谨慎使用。

Okay, let’s install the ArticleBundle to get support for our online magazine website.

好的,让我们安装ArticleBundle以获得对我们在线杂志网站的支持。

弹性搜索 (ElasticSearch)

Unfortunately, the bundle requires ElasticSearch, which could be more straightforward to install. If you’re using Ubuntu 16.04 (like our Homestead Improved box):

不幸的是,该捆绑包需要ElasticSearch ,它可以更直接地安装。 如果您使用的是Ubuntu 16.04(例如改进的Homestead框):

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer

After it’s done (it’ll take a while, as anything with Java), the newly installed version should be set as default on Ubuntu. Elsewhere, you can configure it with:

完成后(与Java一样,将需要一段时间),新安装的版本应在Ubuntu上设置为默认版本。 在其他地方,可以使用以下命令进行配置:

sudo update-alternatives --config java

Finally, set the JAVA_HOME environment variable permanently by editing /etc/environment and adding the line JAVA_HOME="/usr/lib/jvm/java-8-oracle" to the top or bottom of it. Reload this file with source /etc/environment.

最后,通过编辑/etc/environment并在其顶部或底部添加行JAVA_HOME="/usr/lib/jvm/java-8-oracle"来永久设置JAVA_HOME环境变量。 使用source /etc/environment重新加载该文件。

Java is now ready, but we still have to install ES.

Java现在已经准备就绪,但是我们仍然必须安装ES。

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
sudo apt-get install apt-transport-https
echo "deb https://artifacts.elastic.co/packages/5.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-5.x.list
sudo apt-get update && sudo apt-get install elasticsearch
sudo service elasticsearch start

Phew.

ew

Note: Due to RAM requirements, ES takes a while to start up, even if the command executes immediately, so wait a while before trying to curl http://localhost:9200 to test it. If it doesn’t work after a minute or so, go into /etc/elasticsearch/elasticsearch.yml, uncomment network.host and set it to 0.0.0.0. Then restart ES, wait a minute, and try curling again.

注意:由于RAM要求,即使命令立即执行,ES也需要一段时间才能启动,因此请稍等片刻,然后尝试curl http://localhost:9200进行测试。 如果一分钟左右后仍不起作用,请进入/etc/elasticsearch/elasticsearch.yml ,取消注释network.host并将其设置为0.0.0.0 然后重新启动ES,请稍等片刻,然后再次尝试卷曲。

ArticleBundle (ArticleBundle)

Now we can finally install the bundle.

现在,我们终于可以安装该捆绑软件了。

Note: At the time of writing, ArticleBundle is in an experimental state, and Sulu itself is undergoing an RC process. To work with the latest versions of these two main packages, I recommend the following composer.json setup:

注意:在撰写本文时,ArticleBundle处于实验状态,Sulu本身正在进行RC处理。 要使用这两个主要软件包的最新版本,我建议使用以下composer.json设置:

...
"sulu/sulu": "dev-develop as 1.6.0-RC1",
"sulu/article-bundle": "dev-develop"
...
...
"repositories": [
{
"type": "vcs",
"url": "https://github.com/sulu/SuluArticleBundle"
},
{
"type": "vcs",
"url": "https://github.com/sulu/sulu"
}
],
...
...
"minimum-stability": "dev",
"prefer-stable": true
...

Then, install things with composer install, or update with composer update if you’re already working on a running installation. Once both packages are stable, the bundle will be installable via:

然后,使用composer install ,如果已经在运行安装,请使用composer install update进行composer update 。 一旦两个软件包稳定后,即可通过以下方式安装该软件包:

composer require sulu/article-bundle

Now that the bundle is downloaded, we need to add it to the AbstractKernel.php file:

现在已经下载了捆绑软件,我们需要将其添加到AbstractKernel.php文件中:

new Sulu\Bundle\ArticleBundle\SuluArticleBundle(),
new ONGR\ElasticsearchBundle\ONGRElasticsearchBundle(),

In app/config/config.yml we add the following (the sulu_core section should be merged with the existing one):

app/config/config.yml我们添加以下内容( sulu_core部分应与现有的部分合并):

sulu_route:
mappings:
Sulu\Bundle\ArticleBundle\Document\ArticleDocument:
generator: schema
options:
route_schema: /articles/{object.getTitle()}
sulu_core:
content:
structure:
default_type:
article: "article_default"
article_page: "article_default"
paths:
article:
path: "%kernel.root_dir%/Resources/templates/articles"
type: "article"
article_page:
path: "%kernel.root_dir%/Resources/templates/articles"
type: "article_page"
ongr_elasticsearch:
managers:
default:
index:
index_name: su_articles
mappings:
- SuluArticleBundle
live:
index:
index_name: su_articles_live
mappings:
- SuluArticleBundle
sulu_article:
documents:
article:
view: Sulu\Bundle\ArticleBundle\Document\ArticleViewDocument
types:
# Prototype
name:
translation_key:      ~
# Display tab 'all' in list view
display_tab_all:      true

Then, in app/config/admin/routing.yml, we add routes:

然后,在app/config/admin/routing.yml ,我们添加路由:

sulu_arictle_api:
resource: "@SuluArticleBundle/Resources/config/routing_api.xml"
type: rest
prefix: /admin/api
sulu_article:
resource: "@SuluArticleBundle/Resources/config/routing.xml"
prefix: /admin/articles

Add example templates. For templates/articles/article_default.xml:

添加示例模板。 对于templates/articles/article_default.xml

<?xml version="1.0" ?>
<template xmlns="http://schemas.sulu.io/template/template"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="https://www.w3.org/2001/XInclude"
xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/template/template-1.0.xsd">
<key>article_default</key>
<view>articles/article_default</view>
<controller>SuluArticleBundle:WebsiteArticle:index</controller>
<cacheLifetime>144000</cacheLifetime>
<meta>
<title lang="en">Default</title>
<title lang="de">Standard</title>
</meta>
<tag name="sulu_article.type" type="article"/>
<properties>
<section name="highlight">
<properties>
<property name="title" type="text_line" mandatory="true">
<meta>
<title lang="en">Title</title>
<title lang="de">Titel</title>
</meta>
<params>
<param name="headline" value="true"/>
</params>
</property>
<property name="routePath" type="route">
<meta>
<title lang="en">Resourcelocator</title>
<title lang="de">Adresse</title>
</meta>
</property>
</properties>
</section>
<property name="article" type="text_editor">
<meta>
<title lang="en">Article</title>
<title lang="de">Artikel</title>
</meta>
</property>
</properties>
</template>

For views/articles/article_default.html.twig:

对于views/articles/article_default.html.twig

{% extends "master.html.twig" %}
{% block content %}
<h1 property="title">{{ content.title }}</h1>
<div property="article">
{{ content.article|raw }}
</div>
{% endblock %}

Finish initialization:

完成初始化:

php bin/console assets:install # this installs JS, CSS, etc for the UI. Defaults to hard copy, if you want symlinks use `--symlinks`
php bin/console sulu:translate:export # creates translations
php bin/console sulu:document:init # initializes some PHPCR nodes
php bin/console ongr:es:index:create # initializaes the elasticsearch index

Add permissions: in the Admin UI, go to Settings -> User Roles. Select the User role, and scroll down to “Articles”. Select all, save, and refresh the UI to see the changes. The “Articles” option should now appear in the left menu.

添加权限:在管理界面中,转到设置->用户角色。 选择用户角色,然后向下滚动到“文章”。 全选,保存并刷新UI以查看更改。 现在,“文章”选项应出现在左侧菜单中。

Note: If you see the loader spinning indefinitely on this screen, it’s possible your ElasticSearch server powered down because of a lack of RAM on the VM (lack of notification about this has been reported as a bug). ES is very resource intensive, and just running it idle will waste approximately 1.5GB of RAM. The solution is to either power up a machine with more RAM or to restart the ES instance with sudo service elasticsearch start. You can always check if it’s running with sudo service elasticsearch status.

注意:如果在此屏幕上看到加载器无限旋转,则可能是由于VM上没有RAM(由于未通知此错误而已报告为bug ),导致ElasticSearch服务器已关闭电源。 ES占用大量资源,仅在空闲状态下运行将浪费大约1.5GB的RAM 。 解决方案是打开具有更多RAM的计算机,或者使用sudo service elasticsearch start重新启动ES实例。 您始终可以检查它是否以sudo service elasticsearch status运行。

Try writing an example Hello World post and publishing it. It should appear at the url /articles/hello-world if you titled it Hello World.

尝试编写一个示例Hello World帖子并将其发布。 如果将其命名为Hello World它应该显示在url /articles/hello-world

URL方案 (URL Schemes)

The default route setup, as seen in config.yml previously, is articles/{object.getTitle()} for articles. And sure enough, when generated, our article has this URL scheme. But what if we want something like /blog/06/2017/my-title? It’s easy enough to change. Modify config.yml so that route_schema is changed from:

如前面的config.yml所示,默认的路由设置为articles/{object.getTitle()} 。 确实,当生成时,我们的文章具有此URL方案。 但是,如果我们想要/blog/06/2017/my-title怎么办? 更改很容易。 修改config.yml以便将route_schema从以下位置更改:

/articles/{object.getTitle()}

to

/blog/{object.getCreated().format('m')}/{object.getCreated().format('Y')}/{object.getTitle()}

The route fragments between curly braces are being eval’d, and full-stops are being interpreted as method accessors, so, for example, object.getCreated().format('Y') turns into object->getCreated()->format('Y').

花括号之间的路由片段被评估 ,并且句号被解释为方法访问器,因此,例如, object.getCreated().format('Y')变成object->getCreated()->format('Y')

If we try saving a new post now and leaving the resource locator field blank (so that it autogenerates), we get the new route format nicely generated:

如果我们现在尝试保存一个新帖子,并将resource locator字段留空(以便它自动生成),我们将很好地生成新的路由格式:

语言环境 (Locales)

Let’s set up a different language of our site now – we want to cover a wide market, so we’ll build our UI and our content in two languages, when applicable. To add a new language, we edit the webspace file in app/Resources/webspaces. Under localizations, all we need to do is add a new locale:

现在,让我们设置网站的另一种语言-我们希望覆盖广泛的市场,因此,在适用时,我们将使用两种语言构建UI和内容。 要添加新语言,我们在app/Resources/webspaces编辑webspace文件。 在localizations ,我们需要做的就是添加一个新的语言环境:

<localizations>
<localization language="en" default="true"/>
<localization language="hr"/>
</localizations>

HR is for Hrvatski, which is the local name for the Croatian language.

HR代表Hrvatski,这是克罗地亚语的本地名称。

Refreshing the Admin UI now shows a new option in the language selector:

现在,刷新管理界面会在语言选择器中显示一个新选项:

Before we can use this, we must allow the current user to manage this locale. Every locale is by default disallowed for every existing user. To let the current user edit this locale, we go to Contacts -> People -> [YOUR USER HERE] -> Permissions, and under locale we select the new locale, then save and reload the Admin UI.

在使用它之前,我们必须允许当前用户管理此语言环境。 默认情况下,每个现有用户都不允许使用每个区域设置。 要让当前用户编辑此语言环境,请转到联系人->人员-> [您的用户此处]->权限,然后在语言环境下选择新的语言环境,然后保存并重新加载管理界面。



警告语 (A Word of Warning)

After this is done, we MUST run the following console command:

完成此操作后,我们必须运行以下控制台命令:

php bin/adminconsole sulu:document:initialize

This will initialize the PHPCR documents for the new locale. This CANNOT be done after you already create content for the new locales or things will break.

这将为新的语言环境初始化PHPCR文档。 你已经创造了新的语言环境或事物将打破内容后,这不能完成。

Remember to run the sulu:document:initialize command after every locale-related webspace change!

请记住,在每次与语言环境相关的网站空间更改后,都要运行sulu:document:initialize命令!

If you ever forget and end up creating content after a locale was added but before the initialize command was run, the following commands will delete all content related to that locale (so use with care!) and allow you to restart the locale (replace hr in the commands with your own locale identifier(s)).

如果您忘记了添加区域设置后但在运行initialize命令之前最终创建内容,以下命令将删除与该区域设置相关的所有内容(请谨慎使用!),并允许您重新启动区域设置(替换hr在命令中使用您自己的区域设置标识符)。

php bin/adminconsole doctrine:phpcr:nodes:update --query "SELECT * FROM [nt:base]" --apply-closure="foreach(\$node->getProperties('i18n:hr-*') as \$hrNode) {\$hrNode->remove();};"
php bin/websiteconsole doctrine:phpcr:nodes:update --query "SELECT * FROM [nt:base]" --apply-closure="foreach(\$node->getProperties('i18n:hr-*') as \$hrNode) {\$hrNode->remove();};"
php bin/adminconsole sulu:document:initialize

A discussion on how to best warn people about this in the UI is underway.

关于如何在用户界面中最好地警告人们的讨论正在进行中 。



Back to articles now. When on an existing article, switching the locale will summon a popup which lets you either create a new blank article in this language, or create a new article with content that exists in another language (in our case en). Let’s pick the latter.

现在回到文章。 在现有文章上切换语言环境时,将弹出一个弹出窗口,您可以使用该语言创建一个新的空白文章,或者创建包含另一种语言的内容的新文章(在我们的示例中为en )。 让我们选择后者。

The resulting article will be a draft copy of the one we had before.

最终的文章将是我们以前撰写的文章的草稿。

You’ll notice that the URL is the same for this post as it is for its English counterpart. This means we can’t visit it in the browser unless we switch the locale, but we don’t have any kind of locale switcher.

您会注意到,该帖子的网址与其英文对应的网址相同。 这意味着除非切换语言环境,否则我们无法在浏览器中访问它,但是我们没有任何类型的语言环境切换器。

网站空间和语言环境 (Webspaces and Locales)

If you look at the webspace file again, you’ll notice there are portals at the bottom. Portals are like sub-sites of webspaces. In most cases, portals and webspaces will have a 1:1 relationship, but we use portals to define URL routes for different environments. The default sets a specific language via an attribute, and defines the root of all our URLs as merely {host}. Ergo, we get homestead.app in the screenshots above, appended by things like /articles/something or /hello-world.

如果再次查看该Webspace文件,您会注意到底部有portals 。 门户就像网站空间的子站点。 在大多数情况下,门户网站和网站空间将具有1:1的关系,但是我们使用门户网站定义不同环境的URL路由。 默认值通过属性设置特定的语言,并将所有URL的根仅定义为{host} 。 因此,我们在上面的屏幕截图中获得了homestead.app ,并附加了/articles/something/hello-world

To get our different languages to render, we need to change this section. Replace every <url language="en">{host}</url> with <url>{host}/{localization}</url>. This will produce URLs in the form of homestead.app/en/hello-world.

要渲染不同的语言,我们需要更改此部分。 用<url>{host}/{localization}</url>替换每个<url language="en">{host}</url> <url>{host}/{localization}</url> 。 这将以homestead.app/en/hello-world的形式生成URL。

Sure enough, we can now manually switch locale by prefixing all URLs with the locale identifier. It’d be easier if we could just flip a literal switch on the page, though, wouldn’t it?

果然,我们现在可以通过在所有URL的前面加上区域标识符来手动切换区域。 但是,如果我们仅可以在页面上翻转文字开关会更容易,不是吗?

语言环境主题 (Theming for Locales)

Let’s modify our layout so that we have an actual language selector on screen that we can use to change the site’s language.

让我们修改布局,以便在屏幕上有一个实际的语言选择器,可用于更改网站的语言。

In app/Resources/views/master.html.twig, we’ll make the following modification. Right above the form, we’ll put this:

app/Resources/views/master.html.twig ,我们将进行以下修改。 在表格上方,我们将输入以下内容:

<div>
{% for locale, url in urls %}
{% set extra="/"~request.locale %}
<a href="{{ sulu_content_path((url|replace({(extra): ""})?:'/'),request.webspaceKey,locale) }}">{{ locale }}</a>
{% if not loop.last %}&nbsp;|&nbsp;{% endif %}
{% endfor %}
</div>

If we look at the docs, we’ll notice that there’s a urls variable. The urls variable is an associative array from the webspace configuration, containing the URLs of all locales with locales as keys and URLs for values, so we iterate through them. Since we only have one per environment defined, Sulu auto-generates as many as there are locales, blending them with the URL schema defined in the url key.

如果我们看一下docs ,我们会注意到这里有一个urls变量。 urls变量是Webspace配置中的关联数组,包含所有以语言环境为键的语言环境的URL和值的URL,因此我们对它们进行迭代。 由于每个环境只定义了一个环境,因此Sulu会自动生成尽可能多的语言环境,并将它们与url键中定义的URL模式混合。

The URLs contain the language prefix (currently a bug), so we need to strip that. We define this part as extra in Twig ("/"~request.locale means “merge / and request.locale“).

这些URL包含语言前缀(当前是一个错误),因此我们需要删除它。 我们在Twig中将此部分定义为extra部分( "/"~request.locale表示“ merge / and request.locale ”)。

Then, we use the sulu_content_path helper function from vendor/sulu/sulu/src/Sulu/Bundle/WebsiteBundle/Twig/Content/ContentPathTwigExtension.php to feed it the current URL, stripped of the extra content we defined one line above. Additional arguments include the webspace key so it knows where to look for route values to generate, and the locale which to prepend to the content path when returning a new one. Don’t be confused by the ?:'/' part – that’s just a ternary IF which sends along the root route as the parameter (/) if there is no url.

然后,我们使用vendor/sulu/sulu/src/Sulu/Bundle/WebsiteBundle/Twig/Content/ContentPathTwigExtension.phpsulu_content_path帮助器函数为它提供当前URL,除去上面我们在一行中定义的extra内容。 其他参数包括webspace键,以便它知道在哪里寻找要生成的路由值,以及在返回新的时要附加到内容路径的语言环境。 不要被?:'/'部分所迷惑-那只是一个三元IF ,如果没有url ,它会沿根路由作为参数( / )发送。

Finally, we check if this is the last element in the for loop, and if it is, we don’t echo the pipe character, thereby creating a separator all up until the last element.

最后,我们检查这是否是for循环中的最后一个元素,如果是, 则不回显竖线字符,从而创建一个直到最后一个元素的分隔符。

We now have a language switcher in our master layout, and can switch to and from English and Croatian easily.

现在,我们在主布局中有了一个语言切换器,并且可以轻松地在英语和克罗地亚语之间来回切换。

Using this same approach, the language can be turned into a dropdown or any other desired format.

使用相同的方法,可以将语言转换为下拉菜单或任何其他所需的格式。

我们在阴影中做什么 (What We Do in the Shadows)

Finally, we need to do something about the missing translations for pages. If we visit the Homepage while on the hr locale, Sulu will throw a 404 error because that page doesn’t exist in Croatian. Because some pages might not have translations, we want to load an alternative from a secondary language when they’re accessed – the audience may be bilingual and it’d be a shame to discriminate against them just because we don’t have matching content yet.

最后,我们需要对页面缺少的翻译进行处理。 如果我们在hr语言环境中访问主页,Sulu将抛出404错误,因为该页面在克罗地亚语中不存在。 由于某些页面可能没有翻译,因此我们希望在访问它们时从第二语言中加载其他语言-受众可能是双语的,仅由于我们尚无匹配内容而歧视它们是可耻的。

We do this with shadow pages in Sulu. To turn our Croatian version of the Homepage into a shadow page, we do the following:

我们使用Sulu中的影子页面来执行此操作。 要将克罗地亚语版的首页变成阴影页,请执行以下操作:

  • go to the homepage edit screen in the Admin UI while locale is set to English

    语言环境设置为英语时,请转到管理界面中的首页编辑屏幕

  • switch locale and pick “Empty page” in the popup切换语言环境并在弹出窗口中选择“空页面”
  • go to “Settings” of this new page, pick “Enable Shadow”, and select “en” as the locale from which to grab content.转到此新页面的“设置”,选择“启用阴影”,然后选择“ en”作为获取内容的语言环境。

If we now visit the homepage while in the hr locale, it should produce the en homepage, whereas our blog posts will be switchable between the hr and en version. Try it out!

如果我们现在在hr语言环境中访问主页,它应该会生成en主页,而我们的博客文章将可以在hren版本之间切换。 试试看!

结论 (Conclusion)

In this tutorial, we explained some basic Sulu terminology, installed a custom bundle into our Sulu installation, and played around with content. Finally, we set up a basic multi-language news site with a language selector.

在本教程中,我们解释了一些基本的Sulu术语,在我们的Sulu安装中安装了自定义捆绑包,并试用了内容。 最后,我们使用语言选择器建立了一个基本的多语言新闻站点。

One thing to note so far is that Sulu is a very expensive CMS to run – just the ElasticSearch requirement of the ArticleBundle upped the RAM needs of our server to 2-3GB which is by no means a small machine any more, and the vendor folder itself is in the hundreds of megabytes already. But Sulu is about to demonstrate its worth in the future posts – I urge patience until then.

到目前为止,需要注意的一件事是Sulu是运行非常昂贵的CMS –只是ArticleBundle的ElasticSearch要求将我们服务器的RAM需求提高到2-3GB,这已不再是一台小型计算机,而vendor文件夹本身已经达到了数百兆。 但是Sulu即将在以后的文章中展示其价值-我敦促耐心等待。

At this point, Sulu should start feeling more and more familiar and you should be ready for more advanced content. That’s exactly what we’ll focus on in the next part.

此时,Sulu应该开始感到越来越熟悉,您应该已经准备好使用更高级的内容。 这正是我们将在下一部分中重点介绍的内容。

翻译自: https://www.sitepoint.com/set-online-multi-language-magazine-sulu/

如何使用Sulu设置在线多语言杂志相关推荐

  1. 在线C语言编译器/解释器

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在线C语 ...

  2. matlab 编辑器设置,编辑器设置,包括语言、备份和显示设置

    matlab.editor 设置 编辑器设置,包括语言.备份和显示设置 您可以使用 matlab.editor 设置自定义编辑器的视觉外观和行为.使用由 settings 函数返回的根 Setting ...

  3. vscode中文支持xp_VSCode (Visual Studio Code) V1.43.0下载并设置成中文语言的方法

    Visual Studio Code(简称 VS Code / VSC) 是一款免费开源的现代化轻量级代码编辑器,支持语法高亮.智能代码补全.自定义热键.括号匹配.代码片段.代码对比 Diff.GIT ...

  4. Mac设置Office的语言问题

    最近使用office时候发现了一个问题,由于电脑设置默认语言为英文.office也会自动切换为英文语言.想单独改office为中文版.找了一圈没找到方法,搜索了半天,发现很多人无法解决,要么就是修改电 ...

  5. VSCode (Visual Studio Code) V1.43.0下载并设置成中文语言

    Visual Studio Code(简称 VS Code / VSC) 是一款免费开源的现代化轻量级代码编辑器,支持语法高亮.智能代码补全.自定义热键.括号匹配.代码片段.代码对比 Diff.GIT ...

  6. 威纶触摸屏中如何组态设置多国语言进行切换?

    威纶触摸屏中如何组态设置多国语言进行切换? 如果我们在做一些出口的项目时,需要在触摸屏的画面中显示其他的语言,那么如何进行组态设置呢? 我们举个简单的例子来进行说明: 如下图所示,我们新建一个项目,然 ...

  7. 语音转文字怎么设置在线转换的操作

    语音转文字怎么设置在线转换的操作,可能很多人现在还认为录音仅仅只是录音,随着人类的进步,现在还可以把人说的语音转换成文字内容了,什么?你还不会?ok,小编现在就来告诉你语音转文字的在线操作. 第一步: ...

  8. IDEA如何设置为中文语言

    操作步骤如下: 在工具栏找到File选项,在下拉菜单中找到Settings选项,或者直接使用快捷键Ctrl+Alt+S打开设置窗口 选中Plugins(插件),在搜索框输入Chinese,然后找到Ch ...

  9. 计算机语言栏无法设置,Win7电脑语言栏不见了怎么解决?

    最近有Win7用户反映,在使用浏览器搜索问题时,发现无法输入文字,这才发现电脑语言栏不见了,用户反复试了几次,结果都一样,这让用户非常的烦恼.那么,Win7电脑语言栏不见了要怎么解决呢?下面,针对这一 ...

最新文章

  1. mybatis-plus AutoGenerator
  2. Oracle分组函数
  3. 第七章 二叉搜索树(b1)BST:查找
  4. python 自定义模块的发布和安装
  5. 明年的方向是JAVA+SAP
  6. uniapp H5页面嵌入微信小程序 ios 下 video组件 播放视频 设置 border-radius overflow:hidden 不生效
  7. 【FPGA VerilogHDL】第一次尝试:LED灯基础实验
  8. CentOS查看每个进程的网络流量
  9. 文件夹锁定(Source)
  10. Iphone4信号,苹果象个被惯坏的孩子
  11. 纽约部署免费千兆Wi-Fi 30秒可下一部电影
  12. 【性能优化实战】日语java开发相关词汇
  13. 关于j2sdk的设置
  14. IDEA 返回上一步,回到下一步 冲突 快捷键设置
  15. 徘徊过多少橱窗 住过多少旅馆 才会觉得分离也并不冤枉
  16. c++语言打开文件对话框,C++采用openfilename打开文件对话框用法实例
  17. 三个并联电阻计算c语言,3个电阻并联怎么计算
  18. HTTP 204和304的区别
  19. vue-recaptcha 谷歌机器人验证
  20. 台式计算机用u盘给电脑安装系统,台式电脑要怎么进行U盘重装系统

热门文章

  1. 手机中的那些人机交互都是怎么实现的
  2. 什么是大病医保?是商业保险吗?包括哪些病?怎么办理?
  3. CSS3 matrix矩阵
  4. 【使用switch语句】 用C语言编程实现输入年、月、日,编程求这一日是该年中的第几天。
  5. linux下ImageMagick convert命令
  6. 2022年危险化学品生产单位安全生产管理人员考试内容及危险化学品生产单位安全生产管理人员证考试
  7. 《画解数据结构》「基数排序」算法教程
  8. DSPE-PEG-NGR,NGR-PEG-DSPE,磷脂-聚乙二醇-靶向肽NRG
  9. CVPR 2022 | Adobe把GAN搞成了缝合怪!凭空P出一张1024分辨率全身人像
  10. 专题:设计模式(精华篇)(Yanlz+单一职责+里氏替换+依赖倒置+接口隔离+迪米特+开放封闭+创建类+结构类+行为类+立钻哥哥)