I have a website(built with OpenCart) with multiple languages, e.g. English, German, French.
Users can change language using default functionality of the OpenCart - clicking on language icons on top.
Is it possible to send users automaticaly (so they don't have to click on the flag) from :
Germany to German version of the website
France to French version of the website
(English language is default)
Is there an URL I can use for these languages if the default page is for example http://mystore.com ?
(I noticed that when I click on the language icon the URL is not changing - it's the same for all languages)
Nowadays opencart doesn't support this function, but in the past , older versions of Opencart did have this function.
If you want to include this function in your website you will have to do the following:
Edit this file:
catalog/controller/module/language.php
find this:
class ControllerModuleLanguage extends Controller {
protected function index() {
if (isset($this->request->post['language_code'])) {
before the "if", you will have to include the following :
if (isset($this->request->get['lang'])) {
$this->session->data['language'] = $this->request->get['lang'];
if (isset($_SERVER['HTTP_REFERER']) && (strpos($_SERVER['HTTP_REFERER'], $this->config->get('config_url')) !== false) ) {
$this->redirect($_SERVER['HTTP_REFERER']);
} else {
$this->redirect($this->url->link('common/home'));
}
} else {
The source
An example of website with this code:
http://incomingtospain.com/madrid&lang=de
http://incomingtospain.com/madrid&lang=ru
This website has 8 idioms and you can access by different url, with this variable "lang" &lang=es &lang=en ... &lang=de &lang=ru
I think language is set in session variable
For the functionality you mentioned will be achive in following way:
Use the HTML5 geolocation to detect the location of user
Research in opencart to set the language function
after all done place your code using VQMOD if you want to do it in proper way
or you can also edit your core opencart files( Not recommended)
if the browser doesn't support geolocation or they refuse to share their location just load the default language.
With OpenCart 2.0, you must work on the file index.php (in your website root) and place this code :
if (isset($request->get['lang']) && array_key_exists($request->get['lang'], $languages)) {
$session->data['language'] = $request->get['lang'];
}
between line 155 and line 157
Line 153 to 154 :
foreach ($query->rows as $result) {
$languages[$result['code']] = $result;
}
(you add here the new code)
Line 157 :
if (isset($session->data['language']) && array_key_exists($session->data['language'], $languages)) {
Line 158 :
$code = $session->data['language'];
Related
I'm using Typo3 version 10+
I created a "Site package extension" to make some nice templates and styles (header / footer / etc)
I'm using constants like this (constants.typoscript):
#cat=My website variables//a; type=string; label=Some id value
config.some_id = 123
BE User can edit the constant in BE.
To use the constant in fluid template, I use this typoscript code (setup.typoscript)
page = PAGE
page {
typeNum = 0
10 = FLUIDTEMPLATE
10 {
variables {
some_id = TEXT
some_id.value = {$config.some_id}
}
}
...
}
In fluid (footer.html) I use this variable:
<f:link.page pageUid="{some_id}">Some link</f:link.page>
Everything works very nice so far.
Now I'm creating a new extension to output some simple events "Events ext" (list / details)
Now question: is it possible to use this constant (some_id from Site package ext) in the Events extension (List.html) as global variable ?
For some reason I can't see any constants in fluid templates of "Event ext". (empty values)
For both extensions I used the code below and included its configs in Typoscript setup
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile(
$extensionKey,
'Configuration/TypoScript',
'My ext'
);
Constants defined through page.10.variable are only available for page template, not in your extension template.
But you can easily access this variable in your extension with some TypoScript.
Add this TS - in your my_ext/TypoScript/setup.typoscript or through BE in template setup field :
plugin.tx_you_ext.settings {
some_id = {$config.some_id}
}
And then, you can access the data in your Fluid Template with :
{settings.some_id}
On this Sitecore website (6.5.0 rev. 120706), I have this sitecore item called XYZ. So I have http://example.com/XYZ/.
I've added french localization, so using display names I now have:
http://example.com/XYZ-en/
http://example.com/XYZ-fr/
The english version works well, but the french does not and resolves to 404 unless I go to the english first, click on my language switcher button first. When I click on it, I'm redirected to http://example.com/fr-CA/XYZ-fr/, which works. From then on, the english url stops working, the french one works. As I switch languages like that, I always only have one of the two that work.
That button runs this code:
protected void LanguageLinkClick(object sender, EventArgs e)
{
var lang = (Sitecore.Context.Language.Name == "en") ? "fr-ca" : "en";
Tools.RedirectToLanguage(lang, Response);
}
That Tools function runs the following code:
public static void RedirectToLanguage(string pStrLangToSet, HttpResponse pResponse)
{
if (!string.IsNullOrEmpty(pStrLangToSet))
{
var newLang = Language.Parse(pStrLangToSet);
if (newLang != null)
{
Sitecore.Context.SetLanguage(newLang, true);
var itm = Sitecore.Context.Item;
if (Sitecore.Context.Item != null)
{
var itemInLang = Sitecore.Context.Database.Items[itm.ID, newLang];
if (itemInLang != null)
{
pResponse.Redirect(BuildUrl(itemInLang));
}
}
}
}
}
This is somewhat old code that is in this old project.
Is there anything I should look for that would intercept default display name behavior? Or isthis behavior with display names something that's not managed out of the box?
Thanks for any help!
This is the expected behaviour. This article from John West describes the steps involved in the language resolving process and details of the ItemResolver process can be found here.
What I assume you have set in the LinkProvider for your site is useDisplayName=true and maybe languageEmbedding=false, something like the following:
<add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel"
alwaysIncludeServerUrl="false" addAspxExtension="true" encodeNames="true"
languageLocation="filePath" lowercaseUrls="false" shortenUrls="true"
languageEmbedding="never" useDisplayName="true" />
This tells the LinkManager to build URLs using the display name of the Item, hence you have multilingual URLs. Your RedirectToLanguage method switches the context language, from EN to FR-CA and vice versa, which puts Sitecore into that specific language mode for the user.
The following pipeline in <httpRequestBegin> tries to resolve an Item from your requested URL:
<processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel" />
And one of the attempts in that method is to ResolveUsingDisplayName(args). So it will be trying to resolve an Item with an EN display name, but the Context Language is set to FR-CA so in fact it will never find the item, hence the 404.
You have 2 options here:
Set languageEmbedding="always" in your LinkProvider, which mean your URLs will be formatted like "/en/Nice-Product-With-Lots-Of-Options" and "/fr-ca/Mon-Produit-Avec-Plusieurs-Options".
Add a custom pipeline processor after the default ItemResolver which tries to resolve using the alternate language, and if it finds a match sets the Context Item and switches language.
The following will call the default Sitecore ItemResolver after you switch to the alternate language and then attempt to resolve, which will try to find the Item using display name:
public class AlternateLanguageItemResolver : HttpRequestProcessor
{
public override void Process(HttpRequestArgs args)
{
Assert.ArgumentNotNull(args, "args");
if (Context.Item != null || Context.Database == null || args.Url.ItemPath.Length == 0)
return;
var origLanguage = Sitecore.Context.Language;
Sitecore.Context.Language = AltLanguage;
// try to find it using default ItemResolver with alternate language
var itemResolver = new Sitecore.Pipelines.HttpRequest.ItemResolver();
itemResolver.Process(args);
if (Context.Item == null)
{
// well we didn't find it, so switch the context back so everyting can continue as normal
Sitecore.Context.Language = origLanguage;
return;
}
// We found the Item! Switch the User Language for future requests
Sitecore.Context.SetLanguage(AltLanguage, true);
}
private Language _altLanguage = null;
private Language AltLanguage
{
get
{
if (_altLanguage == null)
{
var altLang = (Sitecore.Context.Language.Name == "en") ? "fr-ca" : "en";
_altLanguage = Language.Parse(altLang);
}
return _altLanguage;
}
}
}
And patch it in after the default ItemResolver:
<processor type="Sitecore.Sample.AlternateLanguageItemResolver, Sitecore.Sample"
patch:after="processor[#type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']"/>
This is an untested prototype, check that subsequent requests are returned in the correct switched language. Otherwise redirect back to itself like you in your original code.
So if I understand correctly you'd like these urls to resolve the language for you:
http://example.com/XYZ-en/
http://example.com/XYZ-fr/
The LanguageResolver will resolve the language in this order:
1. language can be distilled from the url (cannot be done with above urls)
2. a language cookie is available for this site (sitename#lang)
3. fall back to default configured language
When you switch, using your switcher, the url paths start with the language code, then the resolver is able to resolve the language by url and persists the language in the language cookie. This is why you experience this behavior of one working language at a time.
The best you can do is always use language in urls (linkprovider configuration), otherwise you'd have to hook in the languageresolver and do some funky check on displayname for each language, but that will probably get very expensive.
The sitecore configuration code below works well in normal mode.
<encodeNameReplacements>
<replace mode="on" find=" " replaceWith="-" />
</encodeNameReplacements>
In Page editor mode the (Spaces) " " or not replaced with "-".
In Page Editor Mode:
If i try to remove image and insert new one; image is not displayed until i saved the page because the (Spaces) " " or not replaced with "-".
Am i missing anything, any ideas will be appreciated.
I had a problem with the encodeNameReplacements messing up the media paths until I found this article.
After implementing this code in our project a dash will replace the %20 and the media images will still render.
Sitecore 7.2 Upgrade Media Library Gotcha
http://getfishtank.ca/blog/sitecore-7-2-upgrade-encoding-media-library-item-names
While upgrading a client to Sitecore 7.2 this section of the release notes gave us pause:
Media API
When rendering media URLs, the system did not use the configuration in the encodeNameReplacements section to replace special characters in the URLs.
This has been fixed so that media URLs also use the encodeNameReplacements configuration. (323105, 314977)
Summary:
media library URLs now use the encodeNameReplacements configuration.
If any one run into this problem; Look for any custom media code written on your site. I got the below custom code causing the problem:
public class MediaProvider : Sitecore.Resources.Media.MediaProvider
{
public override string GetMediaUrl(Sitecore.Data.Items.MediaItem item, Sitecore.Resources.Media.MediaUrlOptions options)
{
string url = base.GetMediaUrl(item, options);
if (!(Sitecore.Context.PageMode.IsNormal && options.UseItemPath))
{
return url;
}
}
}
Working when Changed to
public class MediaProvider : Sitecore.Resources.Media.MediaProvider
{
public override string GetMediaUrl(Sitecore.Data.Items.MediaItem item, Sitecore.Resources.Media.MediaUrlOptions options)
{
string url = base.GetMediaUrl(item, options);
if (options.UseItemPath)
{
return url;
}
}
}
I have a number of PDFs in English language. I have web pages in English and German lang.
If in a German Page I want to display PDF of English lang, it is not possible as that German version PDF is not available, so I tried to do fallback for media library item, even then no help.
So can someone please tell me any alternative for this.
NOTE: I don't want to upload english document in German version, as there are other languages available and customers cannot upload those many times in all lang.
I need to upload a document in Only English but display in all other Languages irrespective of that document is there in that lang or not.
It's ok even if I need to make changes through code.
Thanks in advance
Which template are you using to upload your PDF? If you are using /sitecore/templates/System/Media/Unversioned/Pdf then this inherits from /sitecore/templates/System/Media/Unversioned/File and the blob field for this is marked as shared anyway:
Shared fields are shared across language versions, so if you upload an English PDF and link to that same media item from a German item then it will link to the original English PDF.
In Sitecore, when adding a field to a template, there's a checkbox called "shared". What's it for?
There are a couple of ways to do this. You can do it in the code for your rendering, or you can use the language fallback module from the Sitecore marketplace.
To do it in code you would need to create a new MediaProvider. Create a class that inherits from Sitecore.Resources.Media.MediaProvider and override the protected virtual MediaData GetMediaData(MediaUri mediaUri) method.
This method gets the sitecore item for the context language or the language in the Uri. So you can implement the fall back here:
public class MediaProviderWithFallback : Sitecore.Resources.Media.MediaProvider
{
protected override Sitecore.Resources.Media.MediaData GetMediaData(Sitecore.Resources.Media.MediaUri mediaUri)
{
Assert.ArgumentNotNull((object)mediaUri, "mediaUri");
Database database = mediaUri.Database;
if (database == null)
{
return null;
}
string mediaPath = mediaUri.MediaPath;
if (string.IsNullOrEmpty(mediaPath))
{
return null;
}
Language language = mediaUri.Language;
if (language == null)
{
language = Context.Language;
}
Sitecore.Data.Version version = mediaUri.Version;
if (version == null)
{
version = Sitecore.Data.Version.Latest;
}
Sitecore.Data.Items.Item mediaItem = database.GetItem(mediaPath, language, version);
if (mediaItem == null)
{
return (MediaData)null;
}
// Check for language fallback
if (mediaItem.Versions.Count == 0)
{
// Workout your language fallback here from config or sitecore settings etc...
language = Language.Parse("en");
// Try and get the media item in the fallback language
mediaItem = database.GetItem(mediaPath, language, version);
if (mediaItem == null)
{
return null;
}
}
return MediaManager.Config.ConstructMediaDataInstance(mediaItem);
}
}
Please note - this is untested code. You should store your fallback in config or modify the language template in sitecore.
Once you have that class you will need to update your web.config to use your provider over Sitecores. So find this section in the web.config and change the type to be your class and assembley:
<!-- MEDIA PATH -->
<mediaPath defaultProvider="default">
<providers>
<clear />
<add name="default" type="Sitecore.Resources.Media.MediaPathProvider, Sitecore.Kernel" />
</providers>
</mediaPath>
It's best practice to try to identify whether media will need to be versioned ahead of time. If you know media is going to need to be versioned based on language, you should make sure to update in your web.config the following attribute:
<!--By default, Media items are not versionable and the below setting is set to false in the web.config.
If you upload an image in one language, it will persist across all language versions.
If you change this to true, then versioning will apply and you would have to set the media item into all language versions,
or enable fallback, but if enforce version presence is turned on and media template guids are included in EnforceVersionPresenceTemplates,
then you'll have to make sure all language versions at least exist-->
<setting name="Media.UploadAsVersionableByDefault">
<patch:attribute name="value">true</patch:attribute>
</setting>
Alex Shyba's Partial Language Fallback module will successfully work with this. I would recommend making sure not to enforce version presence on any media templates (don't want to force admins to have to create blank language versions). Then they can create english versions and then only create a language version when they need to override it.
You will need, in the case of using partial language fallback, to make sure the enable fallback checkboxes are checked on the media versionable template fields.
I also recommend updating the media provider so that it embeds language into the media url so that caching doesn't come into play. EG: if you create a pdf named Directions.pdf and it loads at www.site.com/media/Directions.pdf, when you switch between languages, it very well could cache it. So you would want to update the media provider to encode the media url with the context language.
You can see a demo here:
https://github.com/Verndale-Corp/Sitecore-Fallback-FullDemo
public class CustomMediaProvider : MediaProvider
{
public override string GetMediaUrl(MediaItem item, MediaUrlOptions options)
{
Assert.ArgumentNotNull((object)item, "item");
Assert.ArgumentNotNull((object)options, "options");
string result = base.GetMediaUrl(item, options);
// Added by Verndale, check if language should be embedded
UrlOptions urlOptions = UrlOptions.DefaultOptions;
urlOptions = LanguageHelper.CheckOverrideLanguageEmbedding(urlOptions);
if (urlOptions.LanguageEmbedding == LanguageEmbedding.Always && options.UseItemPath)
{
result = "/" + Sitecore.Context.Language.Name.ToLowerInvariant() + Sitecore.StringUtil.EnsurePrefix('/', result);
}
return result;
}
public static UrlOptions CheckOverrideLanguageEmbedding(UrlOptions urlOptions)
{
var thisSite = Sitecore.Context.Site;
if (urlOptions.Site != null)
thisSite = urlOptions.Site;
if (!String.IsNullOrEmpty(thisSite.SiteInfo.Properties["languageEmbedding"]))
{
if (thisSite.SiteInfo.Properties["languageEmbedding"].ToLower() == "never")
urlOptions.LanguageEmbedding = LanguageEmbedding.Never;
else if (thisSite.SiteInfo.Properties["languageEmbedding"].ToLower() == "always")
urlOptions.LanguageEmbedding = LanguageEmbedding.Always;
else if (thisSite.SiteInfo.Properties["languageEmbedding"].ToLower() == "asneeded")
urlOptions.LanguageEmbedding = LanguageEmbedding.AsNeeded;
}
return urlOptions;
}
}
I'm using sitecore 6.5 with two languages installed, en (default) and fr-CA. There are items in the tree with content in both en and fr-CA.
The problem is that the French url has 'fr-CA' in it and we want that to be 'fr', for example:
http://website.com/fr/page.aspx instead of http://website.com/fr-CA/page.aspx
I tried renaming the language from 'fr-CA' to 'fr' and that fixed the url but the content still points to the old language 'fr-CA', so the item shows three languages: en, fr and fr-CA. It's not recognizing the name change.
Any suggestions are much appreciated.
Thanks,
Tarek
The problem is you have created fr-CA versions of your items which cannot be fixed by renaming the language .. you can now make a fr version but, like you are seeing, this means there are now 3 possible versions.
One suggestion is to leave the languages in Sitecore alone and alter how links are served and processed instead.
You would probably need to look at adding your own method into the httpRequestBegin pipeline in Sitecore. This would follow the LanguageResolver entry. You can then parse the RawUrl and set Sitecore.Context.Langauge' to French if the first element in it matched/fr/`.
Extremely quick & dirty example:
public class MyLanguageResolver : HttpRequestProcessor
{
public override void Process(HttpRequestArgs args)
{
string languageText = WebUtil.ExtractLanguageName(args.Context.Request.RawUrl);
if(languageText == "fr")
{
Sitecore.Context.Language = LanguageManager.GetLanguage("fr-CA");
}
}
}
You would probably also have to override the LinkProvider in the <linkManager> section of the web.config to format your URLs when they are resolved by Sitecore.
Another extremely quick & dirty example:
public class MyLinkProvider : LinkProvider
{
public override string GetItemUrl(Sitecore.Data.Items.Item item, UrlOptions options)
{
var url = base.GetItemUrl(item, options);
url = url.Replace("/fr-CA/", "/fr/");
return url;
}
}
Another way (slightly more long-winded as it will need to be executed via a script) is to copy the data from the fr-CA version to the fr version and then delete the fr-CA version of each item.
Rough helper method that encompasses what you're trying to do
private void CopyLanguage(ID id, Language sourceLanguage, Language destinationLanguage)
{
var master = Database.GetDatabase("master");
var sourceLanguageItem = master.GetItem(id, sourceLanguage);
var destinationLanguageItem = master.GetItem(id, destinationLanguage);
using (new SecurityDisabler())
{
destinationLanguageItem.Editing.BeginEdit();
//for each field in source, create in destination if it does not exist
foreach (Field sf in sourceLanguageItem.Fields)
{
if (sf.Name.Contains("_")) continue;
destinationLanguageItem.Fields[sf.Name].Value = sf.Value;
}
destinationLanguageItem.Editing.AcceptChanges();
////Remove the source language version
ItemManager.RemoveVersions(sourceLanguageItem,sourceLanguage, SecurityCheck.Disable);
}
}
Another way to update the languages on your content items is:
Export the fr-CA language to a .xml file (Using the Control Panel)
In the .xml file replace all and tags with the and
Rename fr-CA language in the master database to the fr
Import language from the .xml file
Run Clean Up Databases task (from the Control Panel)
Also you can create a sql script that will change fr-CA language with the fr for all records in the UnversionedFields and VersionedFields tables.
If you need any more information or examples please let me know. :)
I had a similar requirement to rename a language while retaining the content. I decided to migrate content from one language to another by using Unicorn:
1: Create a predicate telling Unicorn to track all of your content. In my case:
<include name="site content" database="master" path="/sitecore/content/mySite" />
Reserialize the content, writing it to disk as YML files
Using a tool that can perform a find & replace in multiple files at once, such as Notepad++, replace all instances of "Language: fr-CA" with "Language: fr" in your yml files.
Run a Unicorn Sync
You will find that all of your content is now associated with the "fr" language instead of "fr-CA".