-
-
Notifications
You must be signed in to change notification settings - Fork 817
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
multi language support for content? #513
Comments
This one pops up regularly. I know it's something a lot of people would like, but i know from experience that doing multilingual is hard if you want to do it right. I mean, we could kludge together something quickly, but I know that doing that will only lead to more support and frustration down the road. Either we do it properly, or we don't do it all for now. |
Thanks a lot. I rather suspected your answer might go that way.... Any chance of getting my hands on the extra code / extension you mentioned in the other issue? That might be enough for me to close this issue ;) |
@ bobdenotter So, any change to you releasing that extension code you mentioned in on #234? |
That code is hopelessly outdated. :-) How I should do it now, is like this:
Now, in the backend you'll have the different contenttypes and the possibility to link them together. However, using this you will get clunky URLs like I know I've promised to write a bit about this. I'd like to get 1.2 out of the door soon, so that I can actually tell people to use the new routing to set up multilingual pages. |
Thanks. sounds good to me. I am happy to wait for 1.2 for now :) |
Hi, I've been playing with Bolt for a bit now but really running into some issues with multi-language content. It could be a bug, it could be the way I'm using it... not sure yet.
Of course things always 'suddenly' work if you start reporting an issue. I will continue with this and see if it actually works now or if I was just lucky for 5 minutes... |
What you've described, should work. That is, as long as all of the pages have a
Or, when you're developing, and like to throw less errors when developing, allow 'empty' as option:
|
@bobdenotter the |
This is my current homepage:
path: /{language}
defaults: { _controller: 'Bolt\Controllers\Frontend::homepage', 'language': 'nl' }
search:
path: /search
defaults: { _controller: 'Bolt\Controllers\Frontend::search' }
preview:
path: /preview/{contenttypeslug}
defaults: { _controller: 'Bolt\Controllers\Frontend::preview' }
requirements:
contenttypeslug: 'Bolt\Controllers\Routing::getAnyContentTypeRequirement'
contentlink:
path: /{language}/{contenttypeslug}/{slug}
defaults: { _controller: 'Bolt\Controllers\Frontend::record' }
requirements:
contenttypeslug: 'Bolt\Controllers\Routing::getAnyContentTypeRequirement'
language: 'nl|en'
taxonomylink:
path: /{taxonomytype}/{slug}
defaults: { _controller: 'Bolt\Controllers\Frontend::taxonomy' }
requirements:
taxonomytype: 'Bolt\Controllers\Routing::getAnyTaxonomyTypeRequirement'
contentlisting:
path: /{language}/{contenttypeslug}
defaults: { _controller: 'Bolt\Controllers\Frontend::listing' }
requirements:
contenttypeslug: 'Bolt\Controllers\Routing::getPluralContentTypeRequirement'
language: 'nl|en' And currently I am unable to reach the Backend. After I managed to login I get: Twig_Error_RuntimeAn exception has been thrown during the rendering of a template ("Parameter "language" for route "contentlink" must match "nl|en" ("" given) to generate a corresponding URL.") in "_listing-base.twig" at line 109. When I set |
Here's how I solved this. I take advantage of Symfony's locale in routes: http://symfony.com/doc/current/book/translation.html#book-translation-locale-url To avoid adding a requirements for this in every route, I added the enforcement in my before, using a list of accepted locales in config. # config.yml
locale: pt_PT
i18n_locales:
- en
- pt
- es
- fr
- de // My\Controller.php
namespace My;
use Bolt\Application;
use Bolt\Controllers\Frontend as BoltFrontend;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class Controller
{
/**
* Enforce locale requirement
*/
public static function before(Request $request, Application $app)
{
BoltFrontend::before($request, $app);
$locales = $app['config']->get('general/i18n_locales', NULL);
if ($locales && $request->getLocale()) {
if (!in_array($request->getLocale(), $locales)) {
$app->abort(404, $app['translator']->trans('Unknown or unsupported locale.'));
}
}
}
/**
* Redirect / to /{default_locale}
*/
public static function i18nFront(Request $request, Application $app)
{
$locales = $app['config']->get('general/i18n_locales', NULL);
if ($locales) {
return $app->redirect($app['paths']['root'] . $request->getPreferredLanguage($locales));
}
}
} Notice how in i18nFront(), I have this on a BaseController so it works in multilingual sites or not. On non-multilingual sites I just don't set i18n_locales in config.yml so this code isn't run. Here's my routes: # routing.yml
homepage:
path: /
defaults:
_controller: 'My\Controller::i18nFront'
# Example for your own pages (notice how simple it is)
somepage:
path: /{_locale}/somepage
defaults:
_controller: 'My\Controller::test'
...
contentlink:
path: /{_locale}/{contenttypeslug}/{slug}
defaults:
_controller: 'Bolt\Controllers\Frontend::record'
_before: 'My\Controller::before'
requirements:
contenttypeslug: 'Bolt\Controllers\Routing::getAnyContentTypeRequirement'
...
i18n_homepage:
path: /{_locale}
defaults:
_controller: 'Bolt\Controllers\Frontend::homepage'
_before: 'My\Controller::before' |
@helderco Interesting! This looks pretty good! You're still using different contenttypes for different languages, I assume? |
@bobdenotter Oh, forgot about that. No, as of now I'm adding internationalised fields to the same content type, which is easier to implement. Example: products:
name: Products
slug: products
singular_name: Product
singular_slug: product
fields:
title_en:
type: text
label: Name (English)
class: large
title_pt:
type: text
label: Name (Portuguese)
class: large
slug:
type: slug
label: URL
uses: title_en
body_en:
type: html
label: Description (English)
height: 150px
body_pt:
type: html
label: Description (Portuguese)
height: 150px
image:
type: image
label: Image
record_template: product.twig
listing_template: products.twig
listing_records: 200
sort: title In Drupal you translate fields now, but behind the scenes it creates translations associations by have a table per field and having a column with the language and another with the translation set id. So you can create a "node" in a specific language, and then translate to another when you're ready and the association between them, as well as knowing which fields are "synchronised" or not, are handled behind the scenes. Would be interesting if we could the the following: products:
name: Products
slug: products
singular_name: Product
singular_slug: product
fields:
title:
type: text
label: Name
i18n: true
class: large
slug:
type: slug
label: URL
uses: title_en
body:
type: html
label: Description
i18n: true
height: 150px
image:
type: image
label: Image
record_template: product.twig
listing_template: products.twig
listing_records: 200
sort: title The available languages for translation could be the i18n_locales config variable. Translating labels (e.g., Name, Description....) and content type name (e.g., Product) would be done through the translator service. Slugs (URLs, e.g. product) could also be translated through the translator service. |
GreaT! |
Excellent ! I am very interested in it Maybe \Bolt\Content can extend a new class like \I18NContent to add i18n field support in contenttype.yml products: class: \I18NContent name: Products slug: products singular_name: Product singular_slug: product fields: title: type: text label: Name i18n: true class: large slug: type: slug label: URL uses: title_en body: type: html label: Description i18n: true height: 150px image: type: image label: Image record_template: product.twig listing_template: products.twig listing_records: 200 sort: title |
@helderco This looks cool and I'm very interested in getting it running myself. How did you manage to only show the correct local field depending on the active language? Another question regarding your configuration:
Here's my Controller:
And my routing.yml homepage:
I'd be grateful for any help. |
I guess just dropping my own controller into app/src/Bolt/controllers is not enough. Where should this go to? |
@klickreflex You're missing the homepage:
path: /
defaults:
_controller: 'My\Controller::i18nFront' Also, the Controller that I gave, can be extended, so it can be reused between projects and keeping it clean from your project specific controller code. As for the local field, I concatenate the field name with the locale, something like: {{ object['field_' ~ app.locale] }} |
I took another look and I see you added the |
Is your Esperanto namespace loading correctly? I mean, is it in your autoloader? Here's my {
"require": {
"bolt/bolt": "dev-master"
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"post-install-cmd": [
"Bolt\\Composer\\ScriptHandler::installAssets"
],
"post-update-cmd": [
"Bolt\\Composer\\ScriptHandler::installAssets"
]
},
"extra": {
"bolt-dir-mode": "0755"
},
"autoload": {
"psr-4": {
"Morfose\\": "app/src"
}
}
} Here, Morfose = My\Controller in my example above. So I have my classes in |
Also, do you have the |
Hi @helderco and thanks a lot for your help. No, I guess my Esperanto namespace is not loading correctly. Which composer.json should it be added to? Sorry, this is a bit of new terrain for me. And yes, I've added
Kind regards, |
It's your project's root composer. I assume you're using composer and have not downloaded Bolt with the full vendors included. I have Bolt in the vendor dir, so if you're using Bolt the default way (download from the site or git clone), then you're seeing Bolt's composer.json which will be different then mine. In the latter case, you'll have something like the following at the end: "autoload": {
"psr-0": {
"Bolt": "app/src/",
"Bolt\\Tests": "app/tests"
}
} Just add yours there. If you have your Esperanto class in Bolt's |
Okay, I did not install via composer but just downloaded the archive. Now I'm all confused about the directory structure. I can find tens of composer.json files, but none of them themes like Also, I do have Bolt in the vendor directory, but inside that there's only a sub directory called Here's a screenshot of my dir structure: |
Bolt itself, if installed in vendor would be in So, in your case, if you want to keep That is, at the top of the homepage:
path: /
defaults: { _controller: 'Bolt\Controllers\Esperanto::i18nFront' } |
I'm feeling like I have to ask stupid question, sorry. I changed the namespace as suggested in both Esperanto.php as well as in my routing and now I get:
|
Show the code. |
|
The namespace should represent the folder it's at (i.e., |
That solved it, thanks a lot! |
Works for me too, thanks. |
I have one more question about this: |
Closing. Use only #234 for discussion on this. See also this informational page on the docs: https://docs.bolt.cm/howto/building-multilingual-websites |
I haven't really seen anything about it, so here is my questions: Is there any support for having the same content in multiple languages?
If not, is there any way of simulating that? The minimum viable feature would be to have a unique key that consists of a content-id and a locale.
I am considering bolt as a backend for managing content in an application that needs to be multilingual. So I would need something that can manage the same content in multiple languages.
ta, mano
The text was updated successfully, but these errors were encountered: