Cannot convert application to multi-lang and keep current content translatable - symfony

We have an application built on Symfony-CMF which is running fine. We now have a requirement to add locales and translations to the content. We have set up one page (/contact) with various locale specific routes (e.g. /en/contact and /fr/contact) and we are able to visit those URLs and edit the content for each language independently. However, we are not able to see the existing content so when we hit /en/contact all the editable content areas are blank.
By rebuilding our app and loading the content (via fixtures) with the relevant multi-lang config in place, we are able to see the original content in place but when we edit it, it seems to edit it for each language. So when we go to /en/contact and edit the content there, we see that change reflected at /fr/contact and vice versa.
We have added the following config:
doctrine_phpcr:
odm:
locales:
en: ~
fr: [en]
de: [en]
cmf_core:
multilang:
locales: [en, fr, de]
We have BasicPage class for our documents:
/**
* #PHPCR\Document(referenceable=true,translator="attribute")
*/
class BasicPage extends Page implements SeoAwareInterface, SitemapElementInterface
{
/**
* #var string
* #PHPCR\String(nullable=true,translated=true)
*/
protected $intro;
...
}
Is there something else we need to do to make the original content translatable?

how do you load the fixtures now? do you use bindTranslation to store content in multiple languages? otherwise you will only create one language version of the content.
when editing, the language you load the document in is the one you store back to, unless you explicitly specify its a different language. (usually, you would change the field that is mapped to the locale of the document).
in your case, if the document is only translated to english currently and you ask for the document in french, phpcr-odm will fall back to english and give you that document. you then edit that and save it back, updating the english version. best is mapping the locale on a field and either expose it to the editor for explicitly specifying the locale or use a content language parameter in the url to avoid confusion.
you can ask the document manager for available translations as well, if you want to show that information.
by the way, we are currently working on providing a tool to convert non-translated documents to translated documents and vice versa: https://github.com/doctrine/phpcr-odm/pull/655 . if you want to check this out, feedback is highly appreciated.

Ok so I managed to figure this out myself (partly due to the info provided by dbu and partly thanks to xdebug!) The cmf_create inline editor was generating ajax requests to update the documents but these were using the default locale rather than the locale specified in the request. Setting cmf_create.rest_force_request_locale to true as specified in the CMF docs worked and means we can edit each language separately when loaded from our fixtures. We still need a migration to make each document translatable but we may be able to leverage the converter tool as mentioned by dbu.

Related

How to add another localization to SULU CMS (System Language)?

I need to add "ru" content localization. So I changed the following fragment:
<localizations>
<localization language="ru" default="true"/>
</localizations>
Then I ran the following command:
php bin/adminconsole sulu:document:initialize
After that, I replaced all the values of a "lang" attributes from "en" to "ru" in all xml-files inside config/templates/pages directory.
But all pages in the administration interface now have empty labels.
I tried changing the value of the "System Language" field in the permissions tab of the contacts to "English". I also reverted all xml-files inside config/templates/pages directory (from "ru" to "en"). Thus the fields become displayed.
So how can I add Russian localization in the "System language" field to solve my problem?
Sulu Core Developer here 🙂
What you have added is another content language, which describes in which languages the page, media, articles and so on can be translated. These languages also appear in the dropdown on the very right of the top toolbar.
However, this language only is about the values the content manager is filling into the fields. All the labels, navigation items and other texts that appear in the UI are displayed based on the system language of the user. Each user can choose their system language in the profile overlay, which will be shown when the name of the user is clicked on the left navigation.
So in order to see the ru titles you have added to the page XML files, the user needs to choose ru as language.
Unfortunately this language does not exist by default in Sulu. So what you can do is to add this language using the configuration in config/packages/sulu_admin.yaml.
sulu_core:
locales:
en: English
de: Deutsch
ru: Russian
translations:
- en
- de
- ru
Afterwards you can download a language using the sulu:admin:download-language command:
bin/console sulu:admin:download-language ru
This will try to download the russian language from our Crowdin Project, which is a crowdsourced translation platform. But I am sorry to say, that the russian translation does not exist there yet. If you want to contribute it, let us know, and we will create the russian language, so that you can start translating it.
If you really just want to add russian titles to the labels, you can still write the YAML configuration as above, and you will see them, when the user chose russian as their system language. All the other texts will fallback to english in that case.

How to customize dexterity-through-the-web-content view?

I created a content in my Plone 4.3 site (no grok here) with the very nice Dexterity through-the-web editor. Now I'd like to customize the default view for this content.
I've read Martn Aspelli's book but the problem is that through-the-web content does'nt have a specific interface (so I can't use it to create my specific view).
If you want to do this all through-the-web, then do the following:
Create a template for your view in the "custom" folder of
portal_skins (through the ZMI). You'll probably want to start with a
copy of something like the page template
(portal_skins/plone_content/document_view). Give it a name like
your_content_type_view. Test it by appending /your_content_type_view
to the URL for a sample object.
Edit the Factory Type Information (portal_types/your_content_type/Default
view method) to be your_content_type_view.
What you will have done is create a skin-level view for the type. This is different from the browser views that Martin is discussing, which do indeed require a class. The Dexterity development team is working on a way to provide TTW maintenance of browser views, but that's for a later version of Plone.
Meanwhile, if you later transfer your Dexterity content type to a Python add on, you'll be able to use your template, possibly unmodified for a browser view.

Changing skin layer based on URL

I am creating a site which will have a "desktop" and a "mobile" theme. I've two theme packages for this site: mysite.theme and mysite.mobile_theme. The mobile_theme is a stripped down version of the desktop theme, with new views and a reduced set of viewlets. I want to switch between these two themes based on the URL the site is visited from (i.e., mobile.mysite.com vs. www.mysite.com).
As the mobile and desktop themes will share a lot of code, mysite.mobile_theme descends from mysite.theme in the following ways:
1) mobile_theme GS skins.xml has a skin path based on the old theme, so the desktop theme's CSS etc. is used:
<skin-path name="mysite.mobile_theme" based-on="mysite.theme">
2) IThemeSpecific marker subclasses the original one, so views which I'm not overriding for the mobile site fallback to the ones in mysite.theme:
from mysite.theme.browser.interfaces import IThemeSpecific as IBaseTheme
class IThemeSpecific(IBaseTheme):
"""Marker interface that defines a Zope 3 browser layer.
"""
3) I have registered various views in mysite.mobile_theme to override the certain ones in mysite.theme.
4) I've used generic setup to have different viewlet registrations for each theme.
At this stage, if I select mysite.mobile_theme in the "Default skin" option portal skins->properties, everything works correctly: my views are used and the viewlets settings from the mobile_theme's GS profile are picked up correctly. So it appears the theme is set up correctly overall.
As mentioned above, however, I would like to swap between these two themes based on URL.
First, I swapped the "Default skin" back to "mysite.theme". I then created an access_rule in the root on my Plone site, roughly following these instructions to select a skin based on URL. It's at plonesite/access_rule and is set up as the access_rule for the plone site:
url = context.REQUEST.get('ACTUAL_URL', '')
if 'mobile' in url:
context.changeSkin('mysite.mobile_theme', context.REQUEST)
else:
context.changeSkin('mysite.theme', context.REQUEST)
I've also tried using context.REQUEST.set('plone_skin', 'mysite.theme') rather than calling context.changeSkin(...).
Using this setup, the viewlets displayed change correctly based on the URL I've used--so it looks like the skin is being changed at some point--but the mysite.mobile_theme's view classes/templates are not being used in preference to mysite.theme's. In summary:
If I call from a URL containing "mobile" I get mysite.theme's views, but mysite.mobile_theme's viewlet registrations.
Otherwise, I get mysite.theme's views and mysite.theme's viewlet registrations.
It looks like I might have to hook into the traversal mechanism to change it so if "mobile" is in the URL, the mysite.mobile_theme's views registered against its IThemeSpecific are chosen rather than the mysite.theme ones, but I'm not sure this is correct nor how I'd go about this.
Can anyone give me some pointers?
UPDATE 3hrs after originally asking
To answer my own question (which I can't do for another 5 hours due to SO's rules):
"""
It would appear that you must patch much lower down in the stack to make this work. I looked at how it was done in plone.gomobile, and they monkeypatch the skin choosing code itself. See:
http://code.google.com/p/plonegomobile/source/browse/gomobile.mobile/trunk/gomobile/mobile/monkeypatch.py
"""
You could use collective.editskinswitcher. Its main use case is to use the Plone Default theme on say edit.example.com and My Custom Theme on www.example.com. You can probably tweak its property sheet to fit your use case though.
Since the 'mobile theme' use case is fairly common I would accept patches to make that easier; or I may work on that myself some time.
(BTW, note that there is a fix-browser-layers branch that may help when you miss some items that are registered for a specific browser layer; seems ready to merge except that I would like to add some tests first.)
I have done this in some prototypes of mobile themes. Please consider thoses two addons not ready for production:
https://github.com/toutpt/plonetheme.jquerymobile
https://github.com/toutpt/plonetheme.senchatouch
The related code is:
The patch on browserlayer to mark the request with my theme layer: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/layer.py
The patch on plonetool to add ##mobile on every content page: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/PloneTool.py
The patch on skintool to tell skin layer is this one if browser layer: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/SkinsTool.py
If you are using plone.app.theming, you also can switch your diazo theme: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/transform.py
Do I understand correctly that at the mobile URL your skins are correct, but your Zope3 Views are not? Which makes sense to me, since the view classes are based on Interfaces. In the same code above, where you use context.changeSkin, add:
from zope.interface import alsoProvides
alsoProvides(context, IMobileView)
and have your view zcml specify for ... IMobileView
[edit: on second thoughts, this really should be what happens when you change the skin - where the additional inteface will be your "IThemeSpecific" - so I'm not sure what's at play here, but it wouldn't hurt to try alsoProvides(context, IThemeSpecific)]

drupal translation t() function doesn't do anything...outputs the same text

I've read that using the t('text to translate') I can translate texts in drupal templates. The problem is, this function doesn't do anything. It simply outputs the same text.
I already have a site and I have installed the proper modules so that's not the problem.
I am using this to translate the titles for the blocks in block.tpl.php.
<h2><?php print t($block->subject); ?></h2>
So this outputs the same original text i'm defining in the title of the view as the block. Why? If I had an error shouldn't Drupal output something or log that error at least?
Translation is not magic. You also need to set up the language of your site in something else than english and be sure that the string you display have a translation.
You can check this at this page : exemple.com/?q=admin/build/translate/search (d6 url)
for the t function to work, you have to do the following:
enable the optional core modules called locale (for interface items) and optionally the content translation (for content).
grant the proper permissions for the proper roles
go to site building -> translate interface to access the interface translation page.
hope that helps
-peter
The translation is not being displayed because its not there. You need to add the translation of that particular string, only then the translated string would be rendered. If you have all the required modules in place, then you need to go to "admin/config/regional/translate/translate" and then search for your string; then click on edit and add the translation of that string.
You also need to install the Locale module and provide translations in the languages you want to support.

How to create custom CSS "on the fly" based on account settings in a Django site?

So I'm writing a Django based website that allows users select a color scheme through an administration interface.
I already have middleware/context processors that links the current request (based on domain) to the account.
My question is how to dynamically serve the CSS with the account's custom color scheme.
I see two options:
Add a CSS block to the base template that overrides the styles w/variables passed in through a context processors.
Use a custom URL (e.g. "/static/dynamic/css/< website_id >/styles.css") that gets routed to a view that grabs all the necessary values and creates the css file.
I'm content with either option, but was wondering if anyone else out there has dealt with similar problems and could give some insight as to "Best Practices".
Update : I'm leaning towards option number 2, as I think this will allow for better caching down the road. So it's dynamic the first time, gets stored in memcache (or whatever), and invalidated when a user updates their settings in the admin site.
Update: Firstly, I'd like to thank everyone for their suggestions thus far. All the answers thus far have focused around generating static files. Though this would work great in production, it feels like a tremendous burden during development. If I wanted to add a new element to be styled, or tweak existing styles I'd have to go through and recreate each and every css file. Sure, this could be done with a management command, but I just don't feel it's worth it. Doing it dynamically would add 1 maybe 2 queries to each page load, which is something I'm not worried about at this stage. All I need to know is that at some point I will be able to cache it without rewriting the whole thing.
I've used option #2 with success. There are 2 decent ways of updating the generated static files that I know of:
Use a version querystring like /special_path.css?v=11452354234 where the v parameter is generated from a database field, key in memcached, or some other persistent file. Version gets updated by admin, or for development you would just make the generation not save if the parameter was something special like v=-1. You'll need a process to clean up the old generations after some time.
Don't use a version querystring, but have it look first for the generated file, if it can't find it, it generates it. You can create a cron job or WSGI app that looks for filesystem changes for development, and have a hook from your admin panel that deletes generations after an update. Here's an example of the monitoring, which you would have to convert to be specific to your generations and not to Django. http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode#Monitoring%5FFor%5FCode%5FChanges
Could generate the css and store it in a textfield in the same model as the user profile/settings. Could then have a view to recreate them if you change a style. Then do your option 1 above.
Nice question.
I would suggest to pre-generate css file after colors scheme is saved. This would have positive impact on caching and overall page loading time. You can store your css files in directory /media/css/custom/<id or stometing>/styles.css or /media/css/custom/<id or sth>.css and in template add <link rel="stylesheet" href="/media/css/custom/{{some_var_pointing _to_file_name}}" />
You can also do the trick with some random number or date in css file name that could be changed each time file is saved. Thanks to this browser will load the file immediately in case of changes.
UPDATE: example of using model to improve this example
To make managing of those file easy you can create simple model (one per user):
class UserCSS(models.Model):
bg_color = models.CharField(..)
...
...
Fields (like bg_color) can represent parts of your css file. You can ovveride save method to add logic that creates css file for user (by rendering some template).
In case your file format change you can make changes in your's model definition (with some default values for new fields), make little changes in template and run save method for each exisintg instance of class. This would renew your css files.
That should work nicely.
I would create an md5 key with the theme elements, store this key in the user profile and create a ccs file named after this md5 key : you gain static file access and automatic theme change detection.

Resources