<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sebastian Helzle</title>
    <description>The latest articles on DEV Community by Sebastian Helzle (@sebobo).</description>
    <link>https://dev.to/sebobo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F287853%2Fa52d86f5-6509-4e3e-bc95-e7f0ea9da703.jpg</url>
      <title>DEV Community: Sebastian Helzle</title>
      <link>https://dev.to/sebobo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sebobo"/>
    <language>en</language>
    <item>
      <title>The translation helper in Neos CMS</title>
      <dc:creator>Sebastian Helzle</dc:creator>
      <pubDate>Tue, 09 Feb 2021 12:16:15 +0000</pubDate>
      <link>https://dev.to/sebobo/the-translation-helper-in-neos-cms-3nbj</link>
      <guid>https://dev.to/sebobo/the-translation-helper-in-neos-cms-3nbj</guid>
      <description>&lt;p&gt;&lt;a href="https://www.neos.io"&gt;Neos CMS&lt;/a&gt; has a very powerful translation helper in its own rendering language &lt;em&gt;Fusion&lt;/em&gt;. It can handle simple translations matching the users language but also more complex localisation options for plural forms and to fill placeholders.&lt;br&gt;
All features derive directly from the the i18n &amp;amp; l10n framework provided by Neos underlying PHP framework &lt;a href="https://flowframework.readthedocs.io/en/stable/"&gt;Flow&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The translation helper
&lt;/h2&gt;

&lt;p&gt;Usually the helper is called in its shorthand form like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myLabel = ${I18n.translate('Vendor.Package:Main:component.label')}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This call means, that in the &lt;em&gt;Vendor.Package&lt;/em&gt; package a &lt;em&gt;Resources/Private/Translations/en&lt;/em&gt; folder exists. Where "en" stands for an English variant and I just used as an example. If you use a different or more languages (and their variants) you should have a folder for each language code.&lt;br&gt;
For our example each language folder would contain at least one file called &lt;em&gt;Main.xlf&lt;/em&gt; and it contains an entry for the id component.label.&lt;/p&gt;

&lt;p&gt;The text for that entry is retrieved and myLabel will contain it. When the user uses a different language and a translation exists, the correct label will be retrieved. If not, a fallback chain is triggered.&lt;br&gt;
The file is structured like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;xliff&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.2"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:xliff:document:1.2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;file&lt;/span&gt; &lt;span class="na"&gt;original=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;product-name=&lt;/span&gt;&lt;span class="s"&gt;"Vendor.Package"&lt;/span&gt; &lt;span class="na"&gt;source-language=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt; &lt;span class="na"&gt;datatype=&lt;/span&gt;&lt;span class="s"&gt;"plaintext"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;trans-unit&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"component.label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;My component&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/trans-unit&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/file&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/xliff&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each trans-unit is a translation unit that can be retrieved in Fusion.&lt;/p&gt;

&lt;p&gt;When having multiple languages defined, the Flow Framework used by Neos will provide the correct translation based on the current frontend language dimension and defined fallback chain.&lt;/p&gt;

&lt;p&gt;The translation file in another language other than the default would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;xliff&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.2"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:xliff:document:1.2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;file&lt;/span&gt; &lt;span class="na"&gt;original=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;product-name=&lt;/span&gt;&lt;span class="s"&gt;"Vendor.Package"&lt;/span&gt; &lt;span class="na"&gt;source-language=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt; &lt;span class="na"&gt;target-language=&lt;/span&gt;&lt;span class="s"&gt;"de"&lt;/span&gt; &lt;span class="na"&gt;datatype=&lt;/span&gt;&lt;span class="s"&gt;"plaintext"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;trans-unit&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"component.label"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;My component&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;target&amp;gt;&lt;/span&gt;Meine Komponente&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/trans-unit&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/file&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/xliff&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It defines the target language and has a target entry for each unit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using arguments and quantities
&lt;/h2&gt;

&lt;p&gt;The translation helper also allows you to provide named and unnamed arguments. This allows you to use placeholders in your text. For named arguments you could use a placeholder like &lt;em&gt;{amount}&lt;/em&gt; to show the number of items in the middle of a text. And in another language the placeholder could be at the end.&lt;br&gt;
Unnamed arguments can be inserted by their index. So the first item would be assigned via &lt;em&gt;{0}&lt;/em&gt; and so on. I always recommend to use named arguments, as it makes managing those translations so much easier. Especially when there are more arguments.&lt;/p&gt;

&lt;p&gt;You can also provide a quantity. This would allow use to not only have a variable in our text like described above, but also have text variants based on the number itself. Many languages have variants for 0, 1 or more items. Some languages have even more differentiations.&lt;/p&gt;

&lt;p&gt;Here is an example of an &lt;a href="https://en.wikipedia.org/wiki/XLIFF"&gt;xliff&lt;/a&gt; file using quantities and arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;xliff&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.2"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:xliff:document:1.2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;file&lt;/span&gt; &lt;span class="na"&gt;original=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;product-name=&lt;/span&gt;&lt;span class="s"&gt;"Vendor.Package"&lt;/span&gt; &lt;span class="na"&gt;source-language=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt; &lt;span class="na"&gt;target-language=&lt;/span&gt;&lt;span class="s"&gt;"de"&lt;/span&gt; &lt;span class="na"&gt;datatype=&lt;/span&gt;&lt;span class="s"&gt;"plaintext"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;group&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"some.label"&lt;/span&gt; &lt;span class="na"&gt;restype=&lt;/span&gt;&lt;span class="s"&gt;"x-gettext-plurals"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;trans-unit&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"component.label[0]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;You see {amount} item&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;target&amp;gt;&lt;/span&gt;Du siehst {amount} Element&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/trans-unit&amp;gt;&lt;/span&gt;               
                &lt;span class="nt"&gt;&amp;lt;trans-unit&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"component.label[1]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;You see {amount} items&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;target&amp;gt;&lt;/span&gt;Du siehst {amount} Elemente&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/trans-unit&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/group&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/file&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/xliff&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the helper
&lt;/h2&gt;

&lt;p&gt;The translation helper looks in its full form like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;translate($id, $originalLabel = null, array $arguments = [], $source = 'Main', $package = null, $quantity = null, $locale = null)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use it in Fusion like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;amount = 5
myAmountLabel = ${I18n.translate('component.amount', '{amount} Items', { amount: this.amount }, 'Main', 'Vendor.Package', this.amount)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every argument of the helper that has a default value can be skipped if not needed. But usually you have to set most to make sure that the translation is fetched from the correct package. As the framework assumes &lt;em&gt;Neos.Neos&lt;/em&gt; as default package name (in the Neos CMS context).&lt;/p&gt;

&lt;h2&gt;
  
  
  A less cluttered variant
&lt;/h2&gt;

&lt;p&gt;The translation helper also has another method that provides a &lt;em&gt;TranslationParameterToken&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can generate one with this call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myLabel = ${I18n.id('component.label')}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myLabel = ${I18n.value('My component')}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this will not yet return a valid translation. The token that is returned provides more methods that can be chained. To make it fully work we again need to provide the same parameters as we did with the previous calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myLabel = ${I18n.id('component.label').package('Vendor.Package').source('Main').translate()}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what did we gain? Nothing yet.&lt;/p&gt;

&lt;p&gt;But if we don‘t call translate() at the end we can reuse our token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i18n = ${I18n.id('').package('Vendor.Package').source('Main')}
myLabel = ${this.i18n.id('component.label').translate()}
myOtherLabel = ${this.i18n.value('Other label').translate()}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see, we can now skip setting the package and source over and over again.&lt;br&gt;
This approach is quite helpful when you use the helper with AFX and the code is less cluttered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you skip the &lt;em&gt;translate()&lt;/em&gt; at the end it will still work correct in most cases as the token has a &lt;em&gt;toString()&lt;/em&gt; implementation. But being explicit can prevent unforeseen errors.&lt;/p&gt;

&lt;p&gt;It‘s always good to have a look at the &lt;a href="https://github.com/neos/flow-development-collection/blob/master/Neos.Flow/Classes/I18n/EelHelper/TranslationHelper.php"&gt;implementation of the helper&lt;/a&gt;. Maybe you spot some more nice features that help you in your project.&lt;/p&gt;

&lt;p&gt;Please contact me if you do and I can add some more hints to this post.&lt;br&gt;
Translating by value&lt;/p&gt;

&lt;p&gt;You might have seen that you can also retrieve translation by their text instead of an id. My personal experience is that this can cause problems when the text changes, meanings change or duplicates appear. So I only use and recommend unique ids. And you can still derive the meaning in the code by providing fallback values if a translation is not available.&lt;br&gt;
Using the helper without Fusion&lt;/p&gt;

&lt;p&gt;If you have Fluid templates, you have a similar helper there. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;f:translate&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"label.id"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you write JavaScript for custom Neos UI plugins or backend modules you can also use the JS version of the helper.&lt;br&gt;
It is available in the &lt;em&gt;Neos.UI&lt;/em&gt; via the &lt;em&gt;i18nRegistry&lt;/em&gt;. And in backend modules as global object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NeosCMS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;I18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Translating labels in Neos allows more flexibility than you might know. Use the token form, quantities and named arguments to make it easier to maintain your code and provide better translations &amp;amp; localisations which take the user into account.&lt;/p&gt;

</description>
      <category>neoscms</category>
      <category>translation</category>
      <category>l10n</category>
      <category>i18n</category>
    </item>
    <item>
      <title>My 10 most favourite Neos CMS settings you might not know yet</title>
      <dc:creator>Sebastian Helzle</dc:creator>
      <pubDate>Fri, 15 May 2020 06:45:39 +0000</pubDate>
      <link>https://dev.to/sebobo/my-10-most-favourite-neos-cms-settings-you-might-not-know-yet-2eoe</link>
      <guid>https://dev.to/sebobo/my-10-most-favourite-neos-cms-settings-you-might-not-know-yet-2eoe</guid>
      <description>&lt;p&gt;Very often I copy &amp;amp; paste settings from existing projects as I need them for most new projects. Or I help other people when they wonder how to achieve certain things in Neos.&lt;br&gt;
To make things easier, here is a list of my top 10 settings in Flow &amp;amp; &lt;a href="https://www.neos.io"&gt;Neos CMS&lt;/a&gt;.&lt;br&gt;
You can add them to your main &lt;em&gt;Settings.yaml&lt;/em&gt; of your site package or create additional &lt;em&gt;Settings.XYZ.yaml&lt;/em&gt; files where &lt;em&gt;XYZ&lt;/em&gt; matches the topic of the settings it contains.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Disable session timeout during development
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
  Flow:
    session:
      inactivityTimeout: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Annoyed when the Neos backend bothers you with a login popup when just wanted to test your new content element?&lt;br&gt;
This will make sure that your backend session is still alive while you've been busy implementing your changes.&lt;/p&gt;

&lt;p&gt;You can put this setting into &lt;em&gt;Development/Settings.yaml&lt;/em&gt; in your Configuration folder, so it's only loaded during development.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Change default languages and fallbacks
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Flow:
        i18n:
            defaultLocale: de
            fallbackRule:
                order: ['fr', 'en']
    Neos:
        userInterface:
            defaultLanguage: de
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changes on the one hand the order in which translations and their fallbacks are loaded for plugins and other frontend code. But also the default backend interface language for new users.&lt;br&gt;
Don't forget the fallbackRule or you might even get errors when your language has missing translations in some package.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Define global image quality
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Media:
        image:
            defaultOptions:
                quality: 95
                webp_quality: 95
                jpeg_quality: 95
                png_compression_level: 95
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defines the default image quality that the configured image library in Neos will use.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Remove application version from HTTP header
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Flow:
        http:
            applicationToken: ApplicationName
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the version of Flow &amp;amp; Neos is contained in the HTTP header. With this setting it will just say &lt;em&gt;"Flow Neos"&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Define initial tree loading depth
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Neos:
        userInterface:
            navigateComponent:
                nodeTree:
                    loadingDepth: 1
                structureTree:
                    loadingDepth: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setting decreases the initial loading depth which can help with large or complex trees and long loading times.&lt;br&gt;
If you have long loading times. Maybe you want to look into using ElasticSearch for querying the page tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Define responsive previews for the backend
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Neos:
        userInterface:
            editPreviewModes:
                iphone:
                    isEditingMode: false
                    isPreviewMode: true
                    fusionRenderingPath: ''
                    title: 'iPhone'
                    position: 100
                    width: 375px
                    height: 667px
                    backgroundColor: 'black'
                ipad:
                    isEditingMode: false
                    isPreviewMode: true
                    fusionRenderingPath: ''
                    title: 'iPad - landscape'
                    position: 100
                    width: 1024px
                    height: 768px
                    backgroundColor: 'black'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These settings allow you to add additional preview modes in the backend to see how the selected page will look on small to large devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Additional groups for the creation dialog
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Neos:
        nodeTypes:
            groups:
                myAdditionalTypes:
                    position:'end'
                    label: 'My additional rarely used types'
                    collapsed: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have a lot of node types? Group them in a smart way and initially collapse groups with rarely needed types.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Disable html suffix in URL generation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Flow:
        mvc:
            routes:
                'Neos.Neos':
                    variables:
                        defaultUriSuffix: ''
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bored of ".html" at the end of your urls? Disable it!&lt;br&gt;
But don't do it in production without a redirect mechanism ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Spot untranslated labels in the backend
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Neos:
        userInterface:
            scrambleTranslatedLabels: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only do this during development!&lt;br&gt;
It will scramble all labels that are using the translation mechanism in Flow / Neos.&lt;br&gt;
Everything that can still be read is either your data or untranslated labels.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Customize your login screen
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neos:
    Neos:
        backendLoginForm:
            backgroundImage: 'resource://My.Site/Public/Images/Login/MyLoginScreen.jpg'
            stylesheets:
                'My.Site:LoginStyles': 'resource://My.Site/Public/Styles/Login.css'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't like are beautiful login background in each Neos version? Or you want to keep the one you like the most? Or you want to have your customer see something related to their company?&lt;br&gt;
Simply change the background image to your liking.&lt;br&gt;
You can even add your own stylesheet to override the Neos logo or make other changes.&lt;br&gt;
Summary&lt;/p&gt;

&lt;p&gt;There are a lot of settings in the Flow &amp;amp; Neos core packages. But the ones I mentioned should solve the most common issues.&lt;br&gt;
But it's always a good idea to go into the Settings.yaml files of the packages you use and have a look around. Maybe you spot a helpful setting too!&lt;/p&gt;

&lt;p&gt;Learn more about my &lt;a href="https://www.helzle.it"&gt;work&lt;/a&gt; or &lt;a href="https://www.neos.io"&gt;Neos CMS&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>neoscms</category>
      <category>configuration</category>
      <category>cms</category>
      <category>helpers</category>
    </item>
    <item>
      <title>How to use "meta"-sprints in Jira to simplify your Scrum process</title>
      <dc:creator>Sebastian Helzle</dc:creator>
      <pubDate>Wed, 18 Dec 2019 09:39:11 +0000</pubDate>
      <link>https://dev.to/sebobo/how-to-use-meta-sprints-in-jira-to-simplify-your-scrum-process-2fnk</link>
      <guid>https://dev.to/sebobo/how-to-use-meta-sprints-in-jira-to-simplify-your-scrum-process-2fnk</guid>
      <description>&lt;p&gt;Many companies use Jira to organise their backlog and to plan sprints. Due to constraints in the software and what happens in everyday Scrum live, this creates some issues for which I present a workaround that solved them during my time as Product Owner.&lt;/p&gt;

&lt;p&gt;Currently I’m spending a large part of my working time as a consultant in a Scrum team at a large telecommunications company.&lt;/p&gt;

&lt;p&gt;I’m mostly focused on helping them building modules and components for their Neos CMS installation. But as part of their team, I’m also following closely how they work with Scrum and related tools.&lt;/p&gt;

&lt;p&gt;In the last 6 years I worked as Product Owner and in other Scrum roles at an agency. I learnt a lot and I also found good solutions for the issues one has, when trying to have a synchronous digital representation your processes. The concept I will explain should also work perfectly fine with any other tool that supports putting stories into sprints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the default sprint list wasn’t enough
&lt;/h2&gt;

&lt;p&gt;At the agency we also worked with Jira and I had to make sure that our customers and my team were able to look at the shared Jira boards and understand what currently happens and what each of them has to do. I also wanted to minimise the chance for errors as that would have led to mistakes, loosing track of important tasks and finally also an increasing amount of work for me to keep track of everything.&lt;/p&gt;

&lt;p&gt;Each customer would have their own board where they can see their backlog, stories that are being prepared and stories that are being worked on. They would prioritise in their board and synchronise this with me, so we could would work on the most important and valuable tasks for their project.&lt;/p&gt;

&lt;p&gt;Internally we would have one board which combined the stories of all the customers (5+) my team worked for. They needed a way to immediately understand what to do next and what they needed to take care of during refinements and plannings. I could always have told them what to do next, but that would have meant, that I needed to remember everything. They would also have a problem, when I’m not there. So over 2 years I worked with our customers and the team on several iterations of „meta“-sprints that would organise the stories in our board in a way that made sense to everyone involved. At the end I had a structure that worked for everybody and I rarely needed to tell anyone where to put new stories or what to work on in the sprint meetings.&lt;br&gt;
I just had to make sure that I prioritised the shared board to make sure that each customers stories where in the right place in relation to each other, and keeping a good overview which stories were coming up that had a high priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different place - same problems
&lt;/h2&gt;

&lt;p&gt;At the mentioned company we currently only work on one project, but it has a very high complexity with many components, dependencies to other teams and stakeholders. During the first few planning sessions and refinements I realised they basically had the same issues as we had with our agency work. People are not always sure where to put stories, what to work on in a meeting and a high dependency on the Product Owner. And there is one ongoing issue with Jira which can cause trouble when you finish a sprint and your unfinished stories get mixed up with the ones already put into the next sprint. I understand from a technical perspective that it’s hard for Jira to find the right spot for each story, especially if you organise them with several boards, but it’s still annoying and can cost a lot of time to sort things the right way again. That’s worse when you have the whole team sitting there and waiting.&lt;/p&gt;

&lt;p&gt;To explain my sprints in a more visual way I set up a simple Jira cloud trial and created some sprints and stories that will help my future rocket startup to fly to the moon and make me rich.&lt;/p&gt;

&lt;p&gt;First I will start almost at the bottom, just above the „Backlog“.&lt;/p&gt;

&lt;h2&gt;
  
  
  The „Upcoming“-sprint
&lt;/h2&gt;

&lt;p&gt;When you work on projects for many years, your backlog can fill up with all kinds of stories. Some people say you should just remove everything that has a certain age, but when working with several customers that can cause diplomatic issues that are sometimes not worth to fight for. So I accepted that we have a certain amount of „zombie“-stories that might at some point happen or they won’t. This lead me to create the first „meta“-sprint. The one called „Upcoming“ (thanks to a certain other PO for coming up with a better name than I did!). This separates the usual backlog from stories that are actually relevant in the foreseeable future or stories that just temporarily fell out of the priority due to some stakeholders decision. I tried keeping the amount of stories in this sprint under 20 to not lose track and create yet another „zombie“ backlog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rN1_qoWG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yqsw1ipnk4shgsceu1r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rN1_qoWG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yqsw1ipnk4shgsceu1r8.png" alt="The upcoming sprint" width="880" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see in the screenshot, the stories in the „Upcoming“-sprint might already have story points as they can even have come from a previously ongoing sprint. If they at some point lose their relevance, then it’s fine to put them into the backlog or simply close them.&lt;/p&gt;

&lt;p&gt;You can see that I used the sprint goal field to clarify what the „meta“-sprint is about. This is an important part as I iterated several times about those texts and verified with each customer, if it made sense to them. I wanted to be sure that their new and old stories always went to the right place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The „Refinement“-sprint
&lt;/h2&gt;

&lt;p&gt;The next „meta“-sprint is the „Refinement“-sprint. It contains all the stories that should be done in the near future and are prepared by the PO to be filled up with details during the Scrum teams refinement meetings. In our Jira workflow these stories were in the „Requirements engineering“ step.&lt;/p&gt;

&lt;p&gt;During those meetings the team would simply go through each story from top to bottom and make sure that each story fulfils their „Definition of ready“. Many teams estimate stories during the planning meetings, which I never liked. Getting an estimate just right before I wanted to put a story into a sprint caused a lot of stress for me. I had almost no time to react when a story got a bigger estimate than I or the stakeholder expected. And I wasn’t able to make sure that all questions which might arise during an estimation could be answered before a new sprint would start. Therefore we had two 1-hour refinement meetings during our 2-week sprints and I had enough time to discuss details or priorities with the stakeholders and split stories if necessary.&lt;br&gt;
And also the team had more time to solve technical questions which might need some outside help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zDkOZ4fW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tep3zfneh8cfac1956au.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zDkOZ4fW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tep3zfneh8cfac1956au.png" alt="The refinement sprint" width="880" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the team was done preparing a story in the refinement meeting, it would have story points and it would be marked as „Open“ in the workflow. That means it could be worked on at any time if prioritised into a sprint. This should represent the "definition of ready" in Scrum with any other requirement your process might have for stories. &lt;/p&gt;

&lt;h2&gt;
  
  
  The „Prioritisation“-sprint
&lt;/h2&gt;

&lt;p&gt;I now had an amount of stories at the top of the „Refinement“-sprint that I could work with as PO. So I put the stories where I was sure they can be prioritised into the next „meta“-sprint called „Prioritisation“-sprint. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vek7SZKo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uokillf5kjtxhs7dyb8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vek7SZKo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uokillf5kjtxhs7dyb8b.png" alt="The prioritisation sprint" width="880" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For some stories the stakeholder just wanted to have an estimation or understand the complexity before making a decision. Those I put into the „Upcoming“-sprint again and assigned them to the person responsible. They could then also decide to put them again into the „Prioritisation“-sprint. Which meant, we as a team could work on them according to the stakeholders / customers priority.&lt;/p&gt;

&lt;p&gt;Having this sprint far away from the backlog keeps you usually from suddenly having a story in there which was just created or someone accidentally put there.&lt;/p&gt;

&lt;p&gt;As we started sprints on Mondays, I always made sure that each customer showed some activity in their priority in the week before, so I knew I could rely on the list for the next sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual sprints
&lt;/h2&gt;

&lt;p&gt;At the top of the screen are the „normal“ sprints. There is the currently active sprint which shows the stories that are in progress and there is the empty sprint that will come next. This one should stay empty until one finishes the current sprint during the next planning meeting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fz4AIYcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ltcdpf8g8b5ct5zdvbt6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fz4AIYcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ltcdpf8g8b5ct5zdvbt6.png" alt="The actual sprints" width="880" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When finishing the current sprint any unfinished stories will move to the next sprint and stay in order. This way you can easily see which stories are unfinished and you can check whether they should go into the next sprint. Sometimes stories are actually done, but someone forgot to close them. This should rather be checked before closing the old sprint, so your metrics show those hard earned story points.&lt;/p&gt;

&lt;p&gt;When this is done, the team can now use the little drag icon at the bottom of the sprint to move stories from the „Prioritisation“-sprint into the next sprint. The story point count will go up and the team can stop when they think they reached the amount they choose to commit to.&lt;/p&gt;

&lt;p&gt;Here you can see the whole board with all sprints:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ooP_LlQd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/m59i59izz8gdigst0mqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ooP_LlQd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/m59i59izz8gdigst0mqe.png" alt="All sprints" width="702" height="905"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other tipps &amp;amp; tricks
&lt;/h2&gt;

&lt;p&gt;When your amount of stories grows bigger, define some filters in the board which allow you to easily spot stories which are in the wrong sprint. Having a filter that just shows stories that are not „ready“ will help you to remove them from the sprints where they don’t fit. Same for other statuses and steps on your workflow.&lt;/p&gt;

&lt;p&gt;I spent a bit of time every month to improve my filters and my Jira dashboard to allow me to spot stories which are not in the right place as fast as possible. For example customers might create „bugs“ which should be monitored and taken care of. But when they are stressed they might put it into the wrong sprint or at the end of the backlog where nobody spots them. Or a developer injects a story into the sprint without telling anyone about it. Your dashboard should just show these kind of mishaps. It’s not about telling people they did something wrong, it’s about making sure, everyone is synchronised.&lt;/p&gt;

&lt;p&gt;If you have a step in your workflow that can mean two things, just insert another step and remove the source of confusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Until recently this system felt so natural to me, that I didn’t think of writing it down. Now I feel that this might help other teams to reduce errors, confusion and to be more effective. Try it out in your Jira or set up a &lt;a href="https://www.atlassian.com/software/jira/try"&gt;trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Every time you feel like things are mixed that should be separate, take a step away from your issue and see if you can divide it into smaller parts. Then conquer them!&lt;/p&gt;

&lt;p&gt;If you did, I would love to know about your experience. And if you have a similar or different system that works great for you, I would also love to know more about that.&lt;/p&gt;

</description>
      <category>jira</category>
      <category>atlassian</category>
      <category>scrum</category>
    </item>
    <item>
      <title>Using Telegram to monitor your Gitlab pipelines</title>
      <dc:creator>Sebastian Helzle</dc:creator>
      <pubDate>Tue, 10 Dec 2019 14:58:39 +0000</pubDate>
      <link>https://dev.to/sebobo/using-telegram-to-monitor-your-gitlab-pipelines-3ga9</link>
      <guid>https://dev.to/sebobo/using-telegram-to-monitor-your-gitlab-pipelines-3ga9</guid>
      <description>&lt;h2&gt;
  
  
  How to be aware of what your pipelines are doing without wallboards and separate browser windows
&lt;/h2&gt;

&lt;p&gt;As a Freelancer I often work with customers who have their own servers, but leave most of the technical work to me. I don't enjoy working directly on servers that much, so the first thing I do when a new server needs to be configured, is installing a Gitlab Runner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up pipelines
&lt;/h2&gt;

&lt;p&gt;This service is then connected to Gitlab.com, the customers Gitlab instance or my own self-hosted Gitlab. Then I set up a deployment pipeline which matches to the project. So for PHP projects I usually choose &lt;a href="https://github.com/TYPO3/Surf"&gt;TYPO3 Surf&lt;/a&gt; to execute actual deployments. &lt;a href="https://deployer.org/"&gt;Deployer&lt;/a&gt; is also an option, but I just got lately into using it more and primarily use it of other tasks. For other kinds of projects you would of course choose the tool which matches best. For Ruby projects it could be &lt;a href="https://capistranorb.com/"&gt;Capistrano&lt;/a&gt;, or you just have a bunch of Shell/Docker scripts.&lt;/p&gt;

&lt;p&gt;After setting up a pipeline in Gitlab to automatically run builds, tests, deployments and other tasks, my project workflow is usually only based on pushing data to Gitlab. So I push via Git and then start working on the next task. Gitlab then handles the rest by communicating to the Gitlab Runner that is running on the server. The runner will then build the project, run some tests and finally deploy new releases. And the whole thing might work out or fail...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zWEFvPTF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/klsaezn5cm3v60zatpew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zWEFvPTF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/klsaezn5cm3v60zatpew.png" alt="List of pipelines in Gitlab" width="880" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to know what the pipeline is doing
&lt;/h2&gt;

&lt;p&gt;So for quite a while I was looking for a way to monitor what happens after builds succeed or fail. I'm usually interested in any kind of failure in any stage of the pipeline, to start fixing the issue. Or success messages, when a deployment went through, after which I like to run some manual tests and inform the customer of the finished update.&lt;/p&gt;

&lt;p&gt;Of course you can simply go to the Gitlab instance and watch the pipeline view and see what's going on. You can also setup awesome wallboards on separate screens, or have a Raspberry PI to create some interesting output. But all these things were to time consuming for me, or didn't work out if I'm working from somewhere else.&lt;/p&gt;

&lt;p&gt;Therefore I was searching for a way to passively monitor the pipelines with the least amount of distraction. After quite some time of searching I found out that a Gitlab integration for the &lt;a href="https://telegram.org/"&gt;Telegram&lt;/a&gt; messenger exists. It's called &lt;a href="https://integram.org/"&gt;Integram&lt;/a&gt;, is Open Source and works really well. It also supports the todo list &lt;a href="https://trello.com/"&gt;Trello&lt;/a&gt; and the code management tool &lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Integram
&lt;/h2&gt;

&lt;p&gt;Integram basically offers a chatbot for Telegram. This bot allows you to interact via messages with your Gitlab instance. You can add hooks to the projects that should be connected and the bot will then inform you of the progress of these projects pipelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WNh_hNCT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/75jirlbdifwbincdcos3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WNh_hNCT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/75jirlbdifwbincdcos3.jpg" alt="Feedback from Gitlab via Telegram" width="880" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As Telegram offers apps for iOS, Android, Mac OS X, Windows etc.. you can receive those messages everywhere. For example, I do a git push with a new release tag, then go make a coffee in the kitchen and a few minutes later my Apple Watch notifies me that the triggered deployment when through.&lt;/p&gt;

&lt;p&gt;If you don't trust the Integram bot, you can also host the service &lt;a href="https://github.com/requilence/integram#how-to-host-integram-on-your-own-server-using-your-private-bots"&gt;yourself&lt;/a&gt;. This way you can keep the whole CI infrastructure to yourself.&lt;/p&gt;

&lt;p&gt;Of course you can also attach the bot to a group chat, so a whole team can be informed.&lt;/p&gt;

&lt;p&gt;Find the information on how to set it up in their &lt;a href="https://github.com/requilence/integram#how-to-use-integram-in-telegram-using-public-bots"&gt;Github repository&lt;/a&gt; based on the integration you need. You basically setup the bot in your Telegram chat and add service hooks to your individual project repositories in Gitlab. The bot will guide you through the whole process. I didn't want to copy the whole procedure here as their readme is always up-to-date and has all the details.&lt;/p&gt;

&lt;p&gt;One note: when you configure the service hook make sure you select all the events you need. I usually select &lt;em&gt;Push Events&lt;/em&gt;, &lt;em&gt;Tag push events&lt;/em&gt;, &lt;em&gt;Job events&lt;/em&gt; and &lt;em&gt;Pipeline events&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In my opinion, the Integram bot is a non-intrusive way of being informed of builds &amp;amp; deployments. As Telegram allows you to treat the chatbot like any other user, you can even mute it for a while if necessary. &lt;br&gt;
If you or your company uses Slack, there are of course integrations which might suit you better. &lt;/p&gt;

</description>
      <category>gitlab</category>
      <category>telegram</category>
      <category>ci</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
