How to get node path from id on multi lingual website? - drupal-7

I have a node, with nid. i.e. 78 and it's on French language (main language is English) so local name to it is:
fr/node/78
or just
node/78
?
Also that page has some alias, i.e. "hello" so it's relative path would be:
/fr/hello
How can I get that relative path?
Yes, I know that:
$alias = drupal_get_path_alias('node/78');
should give me my page alias, but it's not working, probably because of different language?!? Or that should be:
$alias = drupal_get_path_alias('fr/node/78');
I tried both, but none of them is working?!? I can't believe that there is no simple function available, which would take node id as parameter and return SEO (with alias) page path?!?
Please help. What is the easiest way to get node seo path on multi lingual website if I have nid?

Finally I got it. In case somebody else strugles with this:
// Returns root relative path
function get_node_url_ml ($nid, $language){
$defaultLanguage = language_default();
$local_path = 'node/' . $nid;
$url = drupal_lookup_path('alias', $local_path, $language);
if (!$url) $url = 'node/' . $nid;
if ($language != $defaultLanguage->language) $url = $language.'/'.$url;
return '/'.$url;
}

Related

Drupal 7 multilingual site: each node URL is duplicated in all languages

I have a Drupal 7 multilingula site with 3 languages: english, arabic, and chinese.
It all work well, but I've just noticed that pages that are not translated have a duplicated URL for each language.
For example say I have www.example.com/node/12 (default language = English). This node doe snot have any translations.
However www.example.com/ar/node/12 and www.example.com/zh/node/12 both exist and point to the English page. They are even being index in Google.
How can I make these URL show a "Page not found" (which should be the expected behavior)?
There is an other way to translate your content, you can use the Entity Translation module. With this module, you can say that your content is not fully translatable, but just some fields on it (or all if all are translatable). With this system, you have just one node for each language, and this is a better things, if you navigate to your "ar/node/12" the node will be in arabic, if you navigate to the "zh/node/12", the node will be in chinese.
And generally this is better because there is some fields that doesn't need to be translated because it's the same in each language, like an entity reference, an address, etc.
Don't hesitate if you have other question.
Well, in the end I solved it with some custom code in hook_init:
$lang_name = $language->language ;
if ($lang_name == "ar" || $lang_name == "zh-hans") {
$has_translation = false;
if ($is_node) {
$translation_array = translation_node_get_translations($node->tnid);
$has_translation = isset($translation_array[$lang_name]);
}
if (!$has_translation) {
$path = drupal_get_path_alias(current_path());
$installed_languages = language_list();
$en = $installed_languages["en"];
drupal_goto($path, array('language' => $en), 301);
}
}
So, basically, on each page I check if we're on a language other than English (which means we're in a path starting with /ar or /zh). If that's the case and if we're on a node I check if there's an existing translation for that node and that language. If so we do nothing, but if not we redirect to the default path (without the language prefix).

File system path for images

I'm writing a custom helper that extends HtmlHelper and overriding the \HtmlHelper::image() method to calculate the image dimensions and add them as HTML attributes. What I have so far works fine for regular pictures:
public function image($path, $options = array()) {
if (!array_key_exists('width', $options) && !array_key_exists('height', $options)) {
$stamp = Configure::read('Asset.timestamp');
Configure::write('Asset.timestamp', false);
$path = $this->assetUrl($path, $options + array('pathPrefix' => Configure::read('App.imageBaseUrl')));
list($width, $height) = #getimagesize(rtrim(WWW_ROOT, '\\/') . $path);
if (!is_null($width)) {
$options['width'] = $width;
}
if (!is_null($height)) {
$options['height'] = $height;
}
Configure::write('Asset.timestamp', $stamp);
}
return parent::image($path, $options);
}
… but has these flaws:
Pictures from plug-ins can't be located on disk (and they should), e.g.:
echo $this->Html->image('/debug_kit/img/cake.icon.png', array('alt' => 'CakePHP'));
… produces this file system path:
…\src\webroot/debug_kit/img/cake.icon.png
… thus getimagesize() fails because actual location is:
…\src\Plugin\DebugKit\webroot\img\cake.icon.png"
External pictures (which should be ignored) go through the full process:
echo $this->Html->image('http://placekitten.com/200/300');
…\src\webroothttp://placekitten.com/200/300
I've been looking for a builtin method to convert a CakePHP picture URL (in any format accepted by \HtmlHelper::image() into a file system path (o something like null when doesn't apply) but I couldn't find any. Native features that need a disk path, such as \Helper::assetTimestamp() are wrapped in tons of non-reusable code.
Is there an elegant solution?
I'd say that there are pretty much only 3 options:
Submit a patch to add asset filesystem path retrieval functionality to the core.
Copy a lot of code from the helper (assetUrl(), webroot(), and assetTimestamp()).
Use web requests for local URLs (ideally combined with caching).
Try using DS rather than using \ or /, they sometime can cause problems with the OS.
DS is directory separator provided by cakephp Short for PHP’s DIRECTORY_SEPARATOR, which is / on Linux and \ on Windows.
Check the doc

How to get base url with language in joomla 3.4

Trying to get base url in joomla with language suffix like http://localhost/projectname/en
We can easily get http://localhost/projectname/ by using JURI::base
how to get project url with language like
http://localhost/projectname/en
echo $this->baseurl . $this->language;
==> this would give full name of language for ex,en-gb
to avoid this use
if ($this->language == "en-gb")
{
$sef = "en";
}
echo $this->baseurl . $sef;

file path is not retrieved in codeigniter

I am creating an invoice on users desired package selection. The pdf file is being created (but it takes some time), while the code checks for the file. The file exists. Here is the address of the file;
C:/wamp/www/proposal/file/invoice/Basic_52_60.pdf
This is the correct path to the file. I am passing this path to the function in another controller as;
redirect('email/email_invoice/'.$file);
When I tested the file path in email_invoice function, it displayed only c:
c:
The slashes in the path are not transferred. I don't know exactly what is the problem.
CodeIgniter considers each segment of the URL a parameter after the controller and method. So you are essentially passing 7 variables to the Email::email_invoice() method.
You could use some sort of encoding to pass it as one variable and then decode it on the other side such as:
$file = base64_encode($file);
redirect('email/email_invoice/' . $file);
Then in Email.php:
public function email_invoice($file) {
$file = base64_decode($file);
}
Or you could pass it as a get parameter:
redirect('email/email_invoice/?file=' . $file);
public function email_invoice() {
$file = $this->input->get('file');
}
The latter requires the $_GET array to be enabled which it is not by default.
UPDATE - Using Flashdata
Based on some of the comments I thought I would update this answer. base64_encode() can result in characters that will break the URL so you would need to use:
$file = urlencode(base64_encode($file));
redirect('email/email_invoice/' . $file);
And on the other side:
public function email_invoice($file) {
$file = urldecode(base64_decode($file));
}
As the OP pointed out $_GET variables can be manipulated leaving you open to directory traversal attacks or other vulnerabilities. Even if done right you would need extra code for security. Encoding can easily be spotted and altered.
File paths probably shouldn't be carried around in the URL. POST data can be manipulated also even if it is less obvious. Security through obscurity is not security at all. A better approach would be to use flashdata.
$this->session->set_flashdata('email_invoice_pdf', $file);
redirect('email/email_invoice/');
Then in your controller:
public function email_invoice() {
$file = $this->session->flashdata('email_invoice_pdf');
}
That's it. The session was used to carry the file path to the next page request, but after that it is gone.

drupal 7 file field formatter on custom node for javascript (to set up jQuizMe)

I have set up a module with custom node type (I called jquizme, after the javascript jQuizMe that I really like using). I set up two fields for the javascript files I need to supply to make it work (after the general jQuizMe-2.2.js file you need to add another two javascript files - one for settings and one for the quiz content).
Drupal saves the files as myjavascriptfile.js.txt - I tested them and they still work to make the jQuizMe interface - ok. the problem is, I want to add these files on the node page... the files will be different for each node. how can I access the files for the drupal_add_js() function so they will load the files for the node in question?
I tried setting up custom field formatters, but I don't know how to access the uri for the files of a given node automatically to put in the drupal_add_js() function (I can add a static file and it loads fine ... I did this with hook_node_view ( jquizme_node_view ).
So I just need a way to access the info for the files... how are they linked to each node? I can't find the connection.
As you probably noticed, I am a module writing newbie, and I probably won't understand much related to object oriented programming sorry, haven;t progressed to that level yet), but I am open to any answer. I am sure I left out important info, but this it already getting too long.
I also set up a special page earlier on to just see if I could get jQuizMe to work in Drupal so that is still in the code.
I have tried many answers (last six hours or so... too much to say here), the latest of which is using tokens, but that is not working. Here is what I have so far:
function jquizme_node_view($node, $view_mode, $langcode) {
switch ($node->type) {
case 'jquizme':
$items = field_get_items('node', $node, 'field_myfield', $node->language);
drupal_add_css(drupal_get_path('module', 'jquizme') . '/jQuizMe.css', >array('scope' => 'header'));
drupal_add_js(drupal_get_path('module', 'jquizme') . '/alert.js');
drupal_add_js(drupal_get_path('module', 'jquizme') . '/jQuizMe-2.2.js', >array('scope' => 'header'));
//drupal_add_js($tokens['node']['jquizme_js1_field'], array('scope' => >'header'));
//drupal_add_js($tokens['node']['jquizme_js2'], array('scope' => 'header'));
break;
}
}
Thanks in advance!
Can you try this?
// Let me assume that the field names of your two file fields
// are jquizme_js1_field and jquizme_js2_field for convenience..
function jquizme_node_view($node, $view_mode, $language) {
$items = field_get_items('node', $node, 'jquizme_js1_field');
_jquizme_add_js_from_filefield($items);
$items = field_get_items('node', $node, 'jquizme_js2_field');
_jquizme_add_js_from_filefield($items);
}
// Given the values of a filefield attached to some entity,
// adds them as JS files to the page.
function _jquizme_add_js_from_filefield($items = array()) {
foreach ($items as $item) {
$fid = &$item['fid'];
$file = file_load($fid);
if (!$file) {
continue; // Maybe the file got deleted..
}
$wrapper = file_stream_wrapper_get_instance_by_uri($file->uri);
$path = $wrapper->realpath();
// Ensure that the path exists and that it is a Javascript file..
if (file_exists($path) && preg_match('\.js$', $path)) {
drupal_add_js($path, array('type' => 'file'));
}
}
}

Resources