Multilingual site PHP switching method - php

I'm trying to figure out, what I am missing to make two lingual website for PHP pages.
In the root folder, I have index.php and other PHP files along with the include folder, which contains lang-switch.php, navbar.php with other PHP files, footer.php, header.php, etc. navbar.php contains:
<li class="nav-item">
<a class="nav-link" href="?lang=en">En</a>
</li>
<li class="nav-item">
<a class="nav-link" href="?lang=es">Es</a>
</li>
and lang-switch.php:
if (!isset($_SESSION['lang'])){
$_SESSION['lang'] = "en" ;
}else if (isset($_GET['lang']) && $_SESSION['lang'] != $_GET['lang'] && !empty($_GET['lang'])){
if($_GET['lang']){
$_SESSION['lang'] = "en";
} else if ($_GET['lang'] == "es") {
$_SESSION['lang'] = "es";
}
require_once "languages/" . $_SESSION['lang'] . ".php";
}
in the root folder, I also have the languages folder with two files en.php:
$lang = array(
"home" => "Home",
"aboutus" => "About Us",
"contactinfo" => "Contact Information",
"nodatafound" => "No Data Found",
);
and es.php:
$lang = array(
"home" => "Principal",
"aboutus" => "Sobre",
"contactinfo" => "Información del contacto",
"nodatafound" => "Datos no encontrados",
);
then in footer.php, which is in the same includes folder, I include:
include('lang-switch.php');
to pass in html tag:
<div><?php $lang['home'] ?> </div>
<div><?php $lang['aboutus'] ?></div>
I got:
Notice: Undefined variable: lang in
C:\xampp\htdocs\user\site\includes\footer.php on line 16
Notice: Undefined variable: lang in
C:\xampp\htdocs\user\site\includes\footer.php on line 17
with using <?php echo $lang['home'] ?>:
Warning: Illegal string offset 'aboutus' in
C:\xampp\htdocs\user\site\includes\footer.php on line 25
Warning: Illegal string offset 'home' in
C:\xampp\htdocs\user\site\includes\footer.php on line 26

Something like this would probably work for you. I tried to add comments to make it as clear as possible.
Also, this assumes you are using PHP 7.4+ and that you are running session_start() somewhere before this code starts.
I did not test this at all, but is should at least give you a start.
navbar.php
<li class="nav-item">
<a class="nav-link" href="?lang=en">En</a>
</li>
<li class="nav-item">
<a class="nav-link" href="?lang=es">Es</a>
</li>
functions.php or helpers.php or whatever you want
<?php
/**
* Get the current session language
*
* #return string
*/
function getLanguage()
{
// default to 'en' if no language is set yet
return $_SESSION['lang'] ?? 'en';
}
/**
* Set the language based on the `lang` url param
*
* #return void
*/
function setLanguage()
{
$known_languages = [
'en',
'es'
];
// make sure $_GET['lang'] is not empty
// and make sure the new language is known to us
if ( !empty($_GET['lang']) &&
$_SESSION['lang'] !== $_GET['lang'] &&
in_array( $_GET['lang'], $known_languages )
) {
$_SESSION['lang'] = $_GET['lang'];
}
}
/**
* Get the $lang variable with all the translated strings
* This should probably be a JSON file or something similar
*
* #return array
*/
function getTranslations() {
include "languages/" . getLanguage() . ".php";
/* #var array $lang*/
return $lang;
}
/**
* Get the translated string from our list of translations
* Print a translation missing message if not found
*
* #param string $string
* #return string
*/
function getTranslatedString( $string ) {
$string_values = getTranslations();
return $string_values[$string] ?? "Not Translated ( $string )";
}
/**
* Prints the translated string from our list of translations
*
* #param string $string
* #return void
*/
function printTranslatedString( $string ) {
echo getTranslatedString( $string );
}
The translation files stay as you have them, even though you may probably make use of JSON or something similar.
Then, you should run the setLanguage() function somewhere before the output of your HTML starts otherwise you will end up with warnings like:
Warning: Cannot modify header information - headers already sent by
(output started at ...
And then, in your HTML you should be able to use it like:
<div>
<a href="index.php" class="text-dark">
<?php printTranslatedString('home') ?>
</a>
</div>
<div>
<a href="about_us.php" class="text-dark">
<?php printTranslatedString('aboutus') ?>
</a>
</div>

Related

PHP template not rendering to PHP page

I'm trying to make a PHP template without any libraries or frameworks, in order to understand templating. The template is of a <select> that displays a list of all the countries. It was fully working before I templated it, so the issue is not with the <select> element logic.
However, the select template is not rendering to the page.
Here is my code:
country_select.php:
<?php
class CountrySelect {
static $template = 'country_select_template.php';
public static function display() {
if ( class_exists( 'View' ) ) {
// Get the full path to the template file.
$templatePath = dirname( __FILE__ ) . static::$template;
// Return the rendered HTML
return View::render( $templatePath );
}
else {
return "You are trying to render a template, but we can't find the View Class";
}
}
}
?>
country_select_template.php:
<div class="form-group col-sm-6">
<div class="select">
<span class="arr"></span>
<select data-bind="options: _countries,
optionsText: 'name',
optionsValue: 'geonameId',
value: selectedCountry,
optionsCaption: 'Country'">
</select>
</div>
</div>
view.php:
<?php
/** View.php **/
class View {
/**
* -------------------------------------
* Render a Template.
* -------------------------------------
*
* #param $filePath - include path to the template.
* #param null $viewData - any data to be used within the template.
* #return string -
*
*/
public static function render( $filePath, $viewData = null ) {
// Was any data sent through?
( $viewData ) ? extract( $viewData ) : null;
ob_start();
include ( $filePath );
$template = ob_get_contents();
ob_end_clean();
return $template;
}
}
?>
view_renderer.php:
<?php
require('view.php');
?>
Here is the relevant code from the php page where I try to render the template. Notice that the "region_select" is not yet templated, that is how my "country_select used to look.
<div class="row">
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
View::render('country_select_template.php');
?>
<div class="form-group col-sm-6">
<div class="select">
<span class="arr"></span>
<select data-bind="options: _regions,
optionsText: 'name',
optionsValue: 'name',
value: selectedCity,
optionsCaption: 'Region'">
</select>
</div>
</div>
How do I get the html in country_select_template to render to the page? The calling code that is supposed to initiate the template to render to the page is
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
View::render('country_select_template.php');
?>
I have changed the calling code to:
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
echo View::render('country_select_template.php');
?>
I see I have this error in the php error logs:
[15-Feb-2016 09:33:35 Europe/Berlin] PHP Warning:
require(scripts/back_end/views/country_select.php): failed to open
stream: No such file or directory in
/Applications/MAMP/htdocs/its_vegan/index.php on line 92 [15-Feb-2016
09:33:35 Europe/Berlin] PHP Fatal error: require(): Failed opening
required 'scripts/back_end/views/country_select.php'
(include_path='.:/Applications/MAMP/bin/php/php7.0.0/lib/php') in
/Applications/MAMP/htdocs/its_vegan/index.php on line 92
View::render returns the code. It does not print it.
So I think this should do it:
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
echo View::render('country_select_template.php');
?>

Which could be the cause of a variable not being printing in an HTML template called from another PHP class?

I'm developing the base of an MVC project in PHP. I'm advancing with the View part, but something is now working as expected in the rendering of the HTML template.
Here are some contents of the files I'm coding to make this work:
my_project_root/views/templates/humans_list.php
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Humans List</title>
</head>
<body>
<h1>Humans List</h1>
<ul>
<?php foreach($humans as $human) { ?>
<li><?php echo $human ?></li>
<?php } ?>
</ul>
</body>
</html>
my_project_root/views/HumanView.php
<?php
/**
* A class representing a View
*/
class HumanView
{
/** #var array contains a list of names */
var $humans;
/**
* Renders the view in HTML
* #return void
*/
public function render()
{
// Proccess some names to follow some constraints
$this->process($this->humans);
// Here I want to use the template in my view, but
// I need access to the "$humans" variable
require 'templates/humans_list.php';
}
/**
* Proccess humans names to cut surnames for too long names
* #param array &$names
* #return void
*/
private function process(&$names)
{
foreach ($names as $key => $name)
{
if (strlen($name) > 15)
{
$name_parts = explode(' ', $name);
if (isset($name_parts[1])) {
$name_parts[1] = strtoupper(substr($name_parts[1], 0, 1)) . '.';
$names[$key] = implode(' ', $name_parts);
}
else {
$names[$key] = substr($name, 0, 15);
}
}
}
}
// the rest of code
// ...
}
// In my controller I'll use the view and set the names
// retrieved from my model, but to make testing easier I just
// set the object here and set a mock array to test the
// render method, but It doesn't recognize my $humans variable
$view = new HumanView();
$view->humans = [
'John First Smith',
'Peter Second Johnson',
'Marcus Third Willians',
'Lucas Fourth Brown'
];
$view->render();
I expected that the render method printed the HTML from the template with the name in the $human variable as an unordered list (in the ul tag). But as I said before, the variable is not recognized, tough I already set it.
An html more or less like this:
Humans List
John F. Smith
Peter S. Johnson
Marcus T. Willians
Lucas F. Brown
But I just get this:
Human List
Not a single name being printed.
What could be the problem in the code that doesn't let my template to render the variable I just set?
Suppose your template file should also reference the object, since as far as I can see the $humans variable won't automagically jump from the class variable into your method like that. Try this:
<?php foreach($this->humans as $human) { ?>
<li><?php echo $human ?></li>
<?php } ?>

Kohana 3.3.3 multi language site

I'm new to Kohana, using version 3.3.3.1, I'm trying to build a simple dynamic site with the content/pages stored in mySQL DB. The site should have multiple languages. I tried searching everywhere for a good solution/module but I couldn't find anything that works with latest version of Kohana. I tried also this: https://github.com/shockiii/kohana-multilang but it's not working on the latest kohana.
I want to put the language in URL like this (and possibly hide the parameter for the default language):
http://www.domain.com/topics/page-name-here.html -- this would be default EN
http://www.domain.com/de/test/some-page-name-here.html
http://www.domain.com/fr/category/other-page-name-here.html
In my bootstrap.php I have the following route (before adding the language logic):
Route::set('page', '(<category>)(/<pagename>.html)', array(
'category' => '.*',
'pagename' => '.*'))
->defaults(array(
'controller' => 'Page',
'action' => 'index',
));
I want to have all this multi-language logic inside a module if possible. But I read about overriding the Request, URL, Route, and other classes to be able to do that.
What is the best way I can do this? What should I do/change and where to start?
I know this is more a general question, but any help or guidance is greatly appreciated.
Thanks very much!
1) add <lang> into routes in bootstrap.php:
Route::set('default', '((<lang>)(/)(<controller>)(/<action>(/<id>)))', array('lang' => "({$langs_abr})",'id'=>'.+'))
->defaults(array(
'lang' => $default_lang,
'controller' => 'Welcome',
'action' => 'index',
));
- define $default_lang somehow - I use siteconfig.php file placed inside application/config -see below.
2) Extend/redefine factory method in Request Controller:
<?php defined('SYSPATH') or die('No direct script access.');
class Request extends Kohana_Request {
/**
* Main request singleton instance. If no URI is provided, the URI will
* be automatically detected using PATH_INFO, REQUEST_URI, or PHP_SELF.
*
* #param string URI of the request
* #return Request
*/
public static function factory( $uri = TRUE,$client_params = array(), $allow_external = TRUE, $injected_routes = array())
{
$instance = parent::factory($uri);
$index_page = Kohana::$index_file;
$siteconfig = Model_Siteconfig::load();
$lang_uri_abbr = $siteconfig['lang_uri_abbr'];
$default_lang = $siteconfig['language_abbr'];
$lang_ignore = $siteconfig['lang_ignore'];
$ignore_urls = $siteconfig['ignore_urls'];
/* get the lang_abbr from uri segments */
$segments = explode('/',$instance->detect_uri());
$uri_detection = array_intersect($segments, $ignore_urls);
if(empty($uri_detection))
{
$lang_abbr = isset($segments[1]) ? $segments[1]:'';
/* get current language */
$cur_lang = $instance->param('lang',$default_lang);
/* check for invalid abbreviation */
if( ! isset($lang_uri_abbr[$lang_abbr]))
{
/* check for abbreviation to be ignored */
if ($cur_lang != $lang_ignore) {
/* check and set the default uri identifier */
$index_page .= empty($index_page) ? $default_lang : "/$default_lang";
/* redirect after inserting language id */
header('Location: '.URL::base().$index_page . $instance->detect_uri());
die();
}
}
}
return $instance;
}
}
I use "siteconfig" array with language definitions:
array(
'language_abbr' => 'cs',
'lang_uri_abbr' => array("cs" => "česky", "en" => "english"),
'lang_ignore' => 'it',
)
3) Extend/redefine "redirect" method in Controller class for automatic language adding:
<?php defined('SYSPATH') or die('No direct script access.');
class Controller extends Kohana_Controller {
/**
* Issues a HTTP redirect.
*
* Proxies to the [HTTP::redirect] method.
*
* #param string $uri URI to redirect to
* #param int $code HTTP Status code to use for the redirect
* #throws HTTP_Exception
*/
public static function redirect($uri = '', $code = 302)
{
$lng = Request::current()->param('lang');
return HTTP::redirect( (string) '/'.$lng.$uri, $code);
}
}
If You would use HTML class (for templates for example), you should probably redefine some other methods like "anchor" for creating anchors with automatic language adding:
<?php defined('SYSPATH') OR die('No direct script access.');
class HTML extends Kohana_HTML {
/**
* Create HTML link anchors. Note that the title is not escaped, to allow
* HTML elements within links (images, etc).
*
* echo HTML::anchor('/user/profile', 'My Profile');
*
* #param string $uri URL or URI string
* #param string $title link text
* #param array $attributes HTML anchor attributes
* #param mixed $protocol protocol to pass to URL::base()
* #param boolean $index include the index page
* #return string
* #uses URL::base
* #uses URL::site
* #uses HTML::attributes
*/
public static function anchor($uri, $title = NULL, array $attributes = NULL, $protocol = NULL, $index = FALSE)
{
//default language
$lng = Request::current()->param('lang');
if ($title === NULL)
{
// Use the URI as the title
$title = $uri;
}
if ($uri === '')
{
// Only use the base URL
$uri = URL::base($protocol, $index).$lng;
}
else
{
if (strpos($uri, '://') !== FALSE)
{
if (HTML::$windowed_urls === TRUE AND empty($attributes['target']))
{
// Make the link open in a new window
$attributes['target'] = '_blank';
}
}
elseif ($uri[0] !== '#')
{
// Make the URI absolute for non-id anchors
$uri = URL::site($lng.$uri, $protocol, $index);
}
}
// Add the sanitized link to the attributes
$attributes['href'] = $uri;
return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
}
}
I found a great module that is working with Kohana 3.3.3: https://github.com/creatoro/flexilang

Drupal, where i can find footer file?

I need to put some code into the site on drupal and i need this code to work on every page of my site. How can i do this? I wanted to find the file of footer and put some code inside, but i can't find it.
There are 3 ways to add PHP code in to the footer.
1> Turn on the PHP filter & enter the code into a block that is positioned in the footer left region.
2> Put the code in the appropriate template file in the sub-theme.
3> Make a module that outputs the code to a block; activate and place the block.
Suppose that you want to add following line to footer area :
©<?php print date('Y');?> Your Company Name - Address of your company.
So best way to do it is make small module like this:
copyright_block.info
name = Copyright Block
description = Shows the (incrementing) current year and company information.
package = Other
core = 7.x
files[] = copyright_block.module
copyright_block.module
<?php
/**
* #file
* This module shows the copyright year and company information.
*/
/**
* Implements hook_help().
*/
function copyright_block_help($path, $arg) {
if ($path == 'admin/help#copyright_block') {
return t('Manually edit to change company information');
}
}
/**
* Implements hook_block_info().
*/
function copyright_block_block_info() {
$blocks = array();
$blocks['show_copyright'] = array(
'info' => t('Company Information'),
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function copyright_block_block_view($block_name = '') {
if ($block_name == 'show_copyright') {
$content = "<p>©" . date('Y') ." Your Company Name - Address of your company</p>";
$block = array(
'subject' => t('Company Information'),
'content' => $content,
);
return $block;
}
}
NOTE: Do not put PHP end tag ?> at the end.

mix html template with php code : php html template

I create a dynamic website using php/mysql. my template for print data using pure php code + html . now , better, optimized, faster way for Structure of mix php + html ? ( without template engine )
for each page i have : ex.1 ( php code before wrapper )
<?PHP include ( DEFINE_SITE . '/templates/header.php' );
// isset : post : get : SELECT : INSERT ... Or ANY CODE OF PHP
?>
<div id="wrapper">
<div id="leftsidebar"><?PHP // Left DATA ?></div>
<div id="centercontent">
<?PHP // while {} Print result of php ANY LOOPS ..... ?>
</div>
<div id="rightsidebar"><?PHP // Right DATA ?></div>
</div>
<?PHP include ( DEFINE_SITE . '/templates/footer.php' ); ?>
for each page i have : ex.2 ( after side bar and before center content )
<?PHP include ( DEFINE_SITE . '/templates/header.php' );
<div id="wrapper">
<div id="leftsidebar"><?PHP // Left DATA ?></div>
<?PHP // isset : post : get : SELECT : INSERT ... Or ANY CODE OF PHP ?>
<div id="centercontent">
<?PHP // while {} Print result of php ANY LOOPS ..... ?>
</div>
<div id="rightsidebar"><?PHP // Right DATA ?></div>
</div>
<?PHP include ( DEFINE_SITE . '/templates/footer.php' );?>
Which is better? e.x 1 or e.x 2 ? your opinion ?
why the aversion to a template engine? In reality, PHP is a template engine, but perhaps if you checked a few out (like Twig) it might help you in designing something more flexible, fast and responsive without the template engine.... or you might start to love it, like me ;-)
I suggest that you keep your HTML and PHP separated. If you don't want to use a template system why don't you do it like this?
Make a HTML template:
<div id="wrapper">
<div id="leftsidebar">{LEFT}</div>
<div id="centercontent">{CONTENT}</div>
<div id="rightsidebar">{RIGHT}</div>
</div>
In a different php file:
$content = file_get_contents('template.html');
$templateVars = array();
startVar('CONTENT');
echo '<p>This is the content.</p>'; // New template vars are also allowed
endVar('CONTENT');
echo replaceTemplateVars($content);
/**
* Replace template variables recursively with the key-value pairs that are in the $templateVars queue
* #param string $content (default NULL) is code to convert.
* #return the string that is replaced
*/
function replaceTemplateVars($content = NULL)
{
global $templateVars;
$matches = array();
preg_match_all("/{[A-Z0-9_:]*}/", $content, $matches); // $matches = All vars found in your template
foreach($matches[0] as $key)
{
if(isset($templateVars[substr($key, 1, -1)]))
{
$content = str_replace($key, $templateVars[substr($key, 1, -1)], $content); // Substitute template var with contents
}
else
{
$content = str_replace($key, "", $content); // Remove empty template var from template
}
}
// Check if the replacement has entered any new template variables, if so go recursive and replace these too
if(preg_match_all("/{[A-Z0-9_:]*}/", $content, $matches))
{
$content = replaceTemplateVars($content);
}
return $content;
}
/**
* Start output buffer for a template key
* #param string $key is not used. Only for overview purposes
*/
function startVar($key)
{
ob_start();
}
/**
* End output buffer for a template key and store the contents of the output buffer in the template key
* #param string $key
*/
function endVar($key)
{
setVar($key, ob_get_contents());
ob_end_clean();
}
/**
* #param string $key to store value in
* #param mixed $value to be stored
*/
function setVar($key, $value)
{
global $templateVars;
$templateVars[$key] = $value;
}
And this is what you get on your screen:
<div id="wrapper">
<div id="leftsidebar"></div>
<div id="centercontent"><p>This is the content.</p></div>
<div id="rightsidebar"></div>
</div>
So preprocessing is done first and at the end all html code is outputted.
Of course you could add functions like startPrependVar() and startAppendVar() and wrap everything into a Template class to get rid of the global scope.

Categories