Multi-lingual Ghost with same slug - multilingual

I'd like to create a multi-lingual Ghost CMS website, using the same slugs across multi-lingual posts.
e.g.
EN: my-site.com/hello-world
FR: my-site.com/fr/hello-world
I understand from this walkthrough that I need to create the same post multiple times for each language and the slug must be unique. In order to keep things consistent, I'd like to use the same slug (i.e. hello-world) for the same post across each language. Is there a way to do this, perhaps with dynamic routing?

Just thought I'd let you know that we've updated the tutorial you linked to on using different languages in Ghost: https://ghost.org/tutorials/multi-language-content/
You can use matching slugs (I assume you're doing this so you can easily switch languages with a button?) but I wouldn't recommend it as the slug might be used as part of your SEO. A slug written in english isn't going to work as well if someone is searching in french.
The tutorial shows how to create multi-language content and to use <link> elements to add the alternative translations to the meta data. I've created a CodePen demo here on how to create a language select in JavaScript which hooks into those elements: https://codepen.io/daviddarnes/pen/QWwzePz
Hope this helps!

Here is a workaround to achieve that :
Create a template file hello_world.hbs
Update the routes.yaml file as follow
/hello-world/:
template: hello_world # referencing hello_world.hbs
data: page.hello-world # You need to create a page from admin that have slug : /hello-world
/en/hello-world/:
template: hello_world # referencing hello_world.hbs
data: page.hello-word-en # You need to create a page from admin that have slug : /hello-world-en
Write the code of the page in your hello_world.hbs and you can display the content of the page by using the {{#post}}{{/post}} block
🤗 Voila! You have your multi-language pages with same slug

Related

Split single file to multiple "posts" in Hugo?

Hugo's one-file->one-page model is nice and simple, especially for a blog. But sometimes you want to write an "article" for a blog and split it into 2 or more pieces for separate pages (perhaps to be posted on separate days, or whatever).
Is there a way to do this within Hugo? Perhaps a combination of something you put in a layout/theme/shortcode and internal markup within the page (to signal where to split the article)?
Possible models might include:
1 input post "splits" into 2/3/4 posts when the site is built to public
1 input post is duplicated into 2/3/4 posts when the site is built to public but somehow each duplicate isn't an exact duplicate but instead has the whole post but certain parts of the post are hidden/invisible, via CSS, such that they represent the 2/3/4 "pages" of the post.
Or, is this something you do external to Hugo?
UPDATE: I can see I need to clarify this. Consider this random illustrative blog post - it is the third of three closely related posts, and even has a set of links at the top so you can find the earlier posts in the series. Lots of technical blogs do this sort of thing (at least the ones I read).
Now, I'm not looking for a CMS or anything complex. What I do now with Hugo is hugo new posts/an-article-about-constexpr.md and I write one markdown file and it becomes one "post" in standard Hugo fashion. Exactly what you want a SSG to do.
What I want to do is write one markdown file but have some kind of markup in it separating it into sections (like <!-- More --> on steroids) so that instead of generating one page of my site it generates three (in this example) - three separate articles with links from the main page in the "posts" section, etc. etc. And for bonus points, I'd like to generate these "table of contents" sections with links to each of the pages.
So I've been doing that with a cobbled-up awk script that generates pages right next to the post, in the posts directory. I set the post to draft so it doesn't get published, but the pages generated by the awk script have draft=false so they do get published. And the dates get set so they're "in order".
And that's working, but before I invest more time in my little script, I wanted to see if there was a proper way to do this within hugo.
Not sure what you mean by one-file->one-page model.
I have very few parts of any hugo site which one markdown file=one rendered html page.
Could just be the way I build, but everything I've done so far has been vanilla hugo.
To answer your question: Yes, you are correct that would work. There a few ways to do this (I list one below), but maybe a deeper look would be separating the concept of a "tool-chain" and what Hugo is in that tool chain, from a CMS, which Hugo is not.
So, to possibly answer your specific question though:
You can store content in markdown, markdown front matter, or a Data form (XML/JSON) in hugo. Using the page resources {{ .GetPage }} you can access any content and load it in any template or using shortcodes, load it in other markdown.
If I needed to do this as part of a tool chain, i.e. use specific markdown and re-use it in multiple places, I would create a front matter variable, or taxonomy or tag depending on what groupings I needed where, so this was scalable. params such as
"articleAuthor: Jessie P."
"date: DATE HERE"
"tags: etc. etc."
Then lets say I know that's going to be a blog, well fine, then it will be in the corresponding content folder, but if I needed all of Jessie's articles, or articles on that date, or that specific article, I would use the shortcode I make or directly in a template, using .GetPage Match - import the markdown pages I need based on the parameters I need.
But on the other hand, I would need to understand the problem being solved, but, here are a few hugo docs to help you out:
https://gohugo.io/functions/getpage/#readout
https://gohugo.io/content-management/page-bundles/
Remember, Hugo is not a CMS, it is a site generator. If you want a CMS, you can always use Wordpress headless, or any other solution out there.
(off the top of my head using page bundles)
{{ $headlessBundle := .Site.GetPage "/blogs/specific-blog/index" }}
{{ with $getContent := $headlessBundle.Resources.Match "intro.md" }}
{{ (index $getContent 0).Content }}
(You would use various "Where" statements to "filter" content based on the params or however you delineate what you want).
Or for instance if I wanted only the text that had an H1 tag:
{{ $.Scratch.Set "summary" ((delimit (findRE "(<h1.*?>.*?</h1>\\s*)+" .Content) "[…]") | plainify | replaceRE "&" "&" | safeHTML) }}
{{ $.Scratch.Get "summary" }}
Based on the update to the question:
https://discourse.gohugo.io/t/split-markdown-content-in-two-files-but-dont-render-shortcodes-as-raw-text/32080/2
https://discourse.gohugo.io/t/getting-a-list-from-within-a-shortcode/28126
https://discourse.gohugo.io/t/splitting-content-into-sections-based-on-header-level/33749
https://discourse.gohugo.io/t/multiple-content-blocks-on-a-single-page/9092/3
jrmooring answered it best in the above with clear examples and code.
Though, note: If I was doing this in a technical blog this would be integrated into the CMS and coordinated with the builder.

Injecting snippets into a Wagtail StreamField interface

My company is using Wagtail to build robust pages for our website, likely using the StreamField component. We're wondering if Wagtail allows the possibility of us creating reusable parts (perhaps in a snippet), and injecting them into a page.
I'm including a simple diagram of what I'd like to do. Note that while snippets are one possible suggestion, it doesn't need to the specific solution.
The goal of course is to create an element which can be embedded in another page, but can be updated in a single place and cascade everywhere it's used.
Wordpress for example, has a plugin which offers this functionality in short code format:
[embed id=123456]
You can create new block for stream field, let's say MySnippetBlock and then use SnippetChooserBlock to choose the snippet you want.
MySnippetBlock(StructBlock):
title = CharBlock()
snippet = SnippetChooserBlock()
Then in your StreamBlock field you can use above custom block:
MyPage(Page):
stream_field_content = StreamField([('snippet_block', MySnippetBlock())])
...
Or you can use SnippetChooserBlock directly within StreamField if there is no need for additional info attached to it.
stream_field_content = StreamField([('snippet_block', SnippetChooserBlock())])

How to add a telephone link via wagtail?

I am trying to add links in the form 555-555-555 arbitrarily into paragraphs of text on my wagtail site. These phone numbers are currently peppered throughout the site as plain text, but I want to convert them to links.
I found this old wagtail github issue where they explained why they would not add them, but the 'Special-purpose pages' use case they described seems to be different than mine: my site has these numbers in paragraphs of text on most of the content pages (blog, product, marketing, etc).
Can anyone explain how I can add telephone links that can be used throughout the site?
I am using wagtail 1.x
To have telephone link within rich text, you'll need to create a plugin for Hallo.js. Have a look at the documentation and how Wagtail 1.13 creates and register such plugins.
Be aware though that it's usually quite involved and that Wagtail 2.0 rich text editor is now Draftail and Hallo.js is deprecated. Therefore, if you create a Hallo.js plugin and upgrade to Wagtail 2.0, you'll have to add some configuration to continue using Hallo.js or recreate the plugin for Draftail.
FWIW, if you are interested in having a look at what would be involved with creating an plugin for Draftail, you'll need to create an entity (also note that the API for creating entities should receive some enhancements in Wagtail 2.2).
With Raw HTML there is nothing to prevent editors from inserting malicious scripts into the page. Do not use this block. http://docs.wagtail.io/en/v2.1/topics/streamfield.html#rawhtmlblock
A workaround would be a custom filter. Eg:
{{ self.text|richtext|phonify }}
In your templatetags.py:
>>> def phonify(val):
... for tel in re.findall(r'tel:(\d+)', val):
... tag = '{}'.format(tel, tel)
... val = val.replace('tel:{}'.format(tel), tag)
... return val
...
>>> phonify('Hello tel:123 world tel:456!')
'Hello 123 world 456!'
>>>
Now you can instruct editors (via help_text) to add phone numbers like tel:5555555555.
This example does not handle - and +1. But if you figure that out, I'll update the answer ;)
I ended up chopping up my paragraphs and including raw html where I needed to add the tel links. A bit tedious, and the styles were slightly different on some pages, but shorter than doing it any other way.

TYPO3: How can I translate content elements within articles for news?

I am using the news extension: news and have enabled the content element rendering for my articles via extension setup (Use content element relation). This works great and redacteurs can use content elements in the news articles, too.
Furthermore I have localized and translated all the articles So if I switch the language in frontend then the translated articles will show up, but the content elements within this translated articles are still in the default language and not translated. So it seems that the translation of the content elements is not working for me.
For this reason I have checked the language of the content elements within the translated articles again, but the language settings of this content elements looks right:
I don't know what I am doing wrong and hope you can help me?
System:
TYPO3 7.6.12
news 4.3.0
UPDATE
I have found the following ticket: https://forge.typo3.org/issues/67905 and I have tried a updated version of the typoscript in this ticket, but it don't work for me, but maybe is this right way to get the content elements translated, too. Any idea?
I have found the solution :). News use RECORDS for content element rendering. So I have to add some typoscript.
setup.txt or setup area
config {
sys_language_overlay = 1
}

Is it possible for an entry to have two URL in Expression Engine, and translate template names?

I'm currently making a bilingual Expression Engine 2.5.2 website. I'm using this technique to create the two langues, which works perfectly.
I have created a {country_code} global variable in the two index.php files which allows me to detect the current language.
Using this technique, I have no problems to get language-relative data when accessing an entry. My only concern is that I apparently have to privilege a language-specific "clean" URL.
Example entry:
{entry_id} = 123
{title} = My test article
{title_permalink} = my-test-article
{name_fr} = Mon article
{name_en} = My article
If I request http://www.example.com/index.php/en/blog/articles/my-test-article, I expect to to find, in english, "My article" using the template articles in the blog template group.
Everything is fine, but the french translation is accessible when requesting http://www.example.com/index.php/fr/blog/articles/my-test-article. The correct translation of the URL should be http://www.example.com/index.php/fr/blogue/articles/mon-article-test.
Anyone encountered a problem like this? Any solutions via extensions or modules?
I believe the Transcribe module solves this by both providing the ability to translate template group and template names, and having you create a separate entry for each language and piece of content in your site (hence, you have two separate URL titles). But that means buying into their entire methodology for a multi-lingual site.
Myself, I usually just stick to using the entry_id instead of the url_title, and live with the template names being in the primary language.
The best way I found to achieve this is by embedding templates with segment translations, duplicating template groups and duplicating channels.
In the blog/articles template:
{embed="shared/.head" segment_2_translation="blogue" segment_3_translation="articles"}
In the blogue/articles template:
{embed="shared/.head" segment_2_translation="blog" segment_3_translation="articles"}
In shared/.head template:
[...] {if lang == "fr"}English{if:else}Français{/if} [...]
And then you can create a Articles (FR) and a Articles (EN) channels, and each will have their unique URL titles. You can also add a relationship custom field for each channel to associate an entry with it's translation.
It feels messy, but it is the only way I could make it work without modules, plugins or whatnot.

Resources