How to use Twig date to show week day in Chinese text? - php

I want to show the date format like: 10月09日, 周三 (which means 10/9, Wed.)
and my data is UNIX time like [message.time]: 1380813820000
so this is what I do in twig:
{{ (message.time/1000)|date("m月d日, 周w") }}
But it show me: 10月09日,周3, Because date "w" are numbers, not Chinese text.
so can I do anything by Twig to converse the text format?
thanks

The underlying problem is, that Twig uses the DateTime::format method, which does not support locales or (as far as I know) any other type of functionality to translate the names of the weekdays.
There are three solutions:
Use strftime, which supports locales (and thus localized weekday-names).
If you can use the intl extension of PHP, then you can use the Twig-extensions which comes with a intl extension for Twig.
You translate the weekdays by yourself.
Plus to use your preferred solution in a Twig-template, you have to extend the functionality of Twig.
Using strftime and setlocale
The following (rather large) code implements the strftime solution:
<?php
// inspired by phpdude:
// https://github.com/fabpot/twig/issues/378#issuecomment-4698225
class DateTimeHelper_Twig extends Twig_Extension
{
public function getFilters()
{
return array(
'datetime' => new Twig_Filter_Method($this, 'datetime',
array('needs_environment' => true)),
);
}
// This uses `strftime` which makes use of the locale. The format is not
// compatible with the one of date() or DateTime::format().
public function datetime(Twig_Environment $env, $date,
$format = "%B %e, %Y %H:%M", $timezone = null)
{
$date = twig_date_converter($env, $date, $timezone);
return strftime($format, $date->getTimestamp());
}
public function getName()
{
return 'DateTimeHelper';
}
}
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
// Call the setlocale before you use the `datetime` in your templates.
// This only needs to be done once per request.
// If you already have a locale configured in your environment,
// you can replace this with setlocale(LC_TIME, ""); - that way the
// locale of your environment is used.
setlocale(LC_TIME, "zh_CN.UTF-8");
// Add the extension to Twig like that:
$twig->addExtension(new DateTimeHelper_Twig());
$message = array('time' => time() * 1000);
// use the `datetime` filter with %a which gets replaced by the short weekday name of
// the current locale.
echo $twig->render('{{ (message.time/1000)|datetime("%m月%d日, 周%a") }}',
array('message' => $message)), PHP_EOL;
This code shows 10月09日, 周三 on my system (after I installed the debian package locales-all ;-) ).
Of course, locales come with a list of restrictions you probably need to be aware of:
You have to use the correct locale (probably with UTF-8) and the locale you need has to be installed on all the systems which use your code.
Also this solution is not fully platform-independent (on windows setlocale works different/gives different results). Check out the PHP-manual of setlocale
It's easy to screw things up.
Using intl and the Twig-extensions
If you can use the intl extensions and the "Twig-extensions"-package, you have to use localizeddate instead of date:
// add the extension like that
$twig->addExtension(new Twig_Extensions_Extension_Intl());
$message = array('time' => time() * 1000);
echo $twig->render('{{ (message.time/1000)|localizeddate("none", "none", "zh", null, "MM月dd日, eee") }}', array('message' => $message)), PHP_EOL;
That code also shows 10月09日, 周三 - it even adds the 周-thingie automatically.
Of course, the date-format here is also different - check out the ICU user guide.

You can try this code if the setlocale function cannot working on you system.
<?php
require_once dirname(__FILE__).'/vendor/autoload.php';
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
$twig->addFilter(new Twig_SimpleFilter('format_date', function($value) {
$weekdays = array('日','一','二','三','四','五','六');
return sprintf("%s, 周%s", date("m月d日"), $weekdays[date("w")]);
}));
echo $twig->render('{{ time_at | format_date }}', array(
'time_at' => 1380813820000/1000
));

I found a quick filter replace , here is the code snippet:
<div class="date"><span>{{ (create_time/1000)|date("m月d日,周D")|replace({'Mon':'一','Tue':'二','Wed':'三','Thu':'四','Fri':'五','Sat':'六','Sun':'日'}) }}</span></div>

Related

SilverStripe overwriting URLSegmentFilter static

URLSegmentFilter has a static array $default_replacements which holds, among others, the string to convert ampersands to (from & to -and-) for URL's.
I'm trying to extend the class and overwrite this static to translate the ampersand convert (only value is english and).
How can I overwrite the owner static for this goal?
class URLSegmentFilterExtension extends Extension {
private static $default_replacements = array(
'/&/u' => '-and-', // I need to translate this using _t()
'/&/u' => '-and-', // And this one
'/\s|\+/u' => '-',
'/[_.]+/u' => '-',
'/[^A-Za-z0-9\-]+/u' => '',
'/[\/\?=#]+/u' => '-',
'/[\-]{2,}/u' => '-',
'/^[\-]+/u' => '',
'/[\-]+$/u' => ''
);
}
First of all: The URLSegmentFilter mainly operates in the CMS context, where you usually just have a single locale (depending on the settings of the editing Member). So using _t() alone might not be very helpful? So you'd probably have to get the current editing locale (assuming you're using Fluent or Translatable) and set the locale for translations temporarily.
I don't see a way to hook in translations via an Extension there. I think you'd be better off creating a custom subclass and use it via Injector.
Something like this should work:
<?php
class TranslatedURLSegmentFilter extends URLSegmentFilter
{
public function getReplacements()
{
$currentLocale = i18n::get_locale();
$contentLocale = Translatable::get_current_locale();
// temporarily set the locale to the content locale
i18n::set_locale($contentLocale);
$replacements = parent::getReplacements();
// merge in our custom replacements
$replacements = array_merge($replacements, array(
'/&/u' => _t('TranslatedURLSegmentFilter.UrlAnd', '-and-'),
'/&/u' => _t('TranslatedURLSegmentFilter.UrlAnd', '-and-')
));
// reset to CMS locale
i18n::set_locale($currentLocale);
return $replacements;
}
}
Then you have to enable the custom URLSegmentFilter via config by putting something like this in your mysite/_config/config.yml file:
Injector:
URLSegmentFilter:
class: TranslatedURLSegmentFilter
Update: The above example assumes you're using the Translatable module. If you're using Fluent, replace the following line:
$contentLocale = Translatable::get_current_locale();
with:
$contentLocale = Fluent::current_locale();
You can update configuration dynamically in mysite/_config.php
$defaultReplacements = Config::inst()->get('URLSegmentFilter', 'default_replacements');
$translatedAnd = _t('URLSegmentFilter.And','-and-');
$defaultReplacements['/&/u'] = $translatedAnd;
$defaultReplacements['/&/u'] = $translatedAnd;
Config::inst()->Update('URLSegmentFilter', 'default_replacements', $defaultReplacements);

Symfony + Doctrine Oracle DateTime format issue

I have a problem with Oracle DateTime type in Symfony 2.7 + Doctrine.
I have a table with a DateTime column which is mapped in Symfony through Doctrine.
When I try to persiste the relative Entity I got the following error:
Could not convert database value "31-MAY-16 03.56.49.000000 PM" to Doctrine Type datetime. Expected format: Y-m-d H:i:s File: .../vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php Line: 63
I cannot change the default format in the Oracle Database.
I previously fixed the problem by modifing the method getDateTimeFormatString() in the vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php and it worked.
However, since I have to use Git and "composer install ..." in order to deploy my application in production environment, all vendors are installed from the Symfony repository; in that way I lose the changes I made in OraclePlatform.php
To solve the problem without touching the verdors libraries, i tried to set the following Oracle ENV variables on httpd init start script but it doesn't work
export NLS_TIME_FORMAT="HH24:MI:SS"
export NLS_DATE_FORMAT="YYYY-MM-DD HH24:MI:SS"
export NLS_TIMESTAMP_FORMAT="YYYY-MM-DD HH24:MI:SS"
export NLS_TIMESTAMP_TZ_FORMAT="YYYY-MM-DD HH24:MI:SS TZH:TZM"
I found a possible solution in the Known Vendor Issues in the Doctrine documentation about PostgreSQL where they suggest to use the VarDateTimeType by overriding the type like this:
use Doctrine\DBAL\Types\Type;
Type::overrideType('datetime', 'Doctrine\DBAL\Types\VarDateTimeType');
Type::overrideType('datetimetz', 'Doctrine\DBAL\Types\VarDateTimeType');
Type::overrideType('time', 'Doctrine\DBAL\Types\VarDateTimeType');
This seams to be the solution, however I have no idea on how to override the type with the code above but mostly where to put the above code.
Do someone have any idea?
Thanks
P.S. I'm using DateTime without timezone
Create a custom DBAL Type extending the DateTimeType and override the convertToPHPValue function (I copied the VarDateTimeType class, which couldn't successfully convert the Date type my Oracle installation was using):
<?php
namespace YourCompany\SomeBundle\Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeType;
class SillyDateTimeType extends DateTimeType
{
/**
* {#inheritdoc}
* #throws \Doctrine\DBAL\Types\ConversionException
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === null || $value instanceof \DateTime) {
return $value;
}
$val = \DateTime::createFromFormat('d-M-y H.i.s.u A', $value);
if ( ! $val instanceof \DateTime) {
throw ConversionException::conversionFailed($value, $this->getName());
}
return $val;
}
}
Replace $val = \DateTime::createFromFormat('d-M-y H.i.s.u A', $value); with whatever format your installation is returning for those columns.
Then just register it under dbal in config.yml:
# app/config/config.yml
doctrine:
dbal:
types:
sillydatetime: YourCompany\SomeBundle\Doctrine\DBAL\Types\SillyDateTimeType
Now you can use sillydatetime (or whatever you call it) anywhere in your column type specifications.
I fixed the problem following the proposal of this comment in Github. In app/config/config.yml (Symfony 2.3.1) I added the following block:
services:
oracle.listener:
class: Doctrine\DBAL\Event\Listeners\OracleSessionInit
tags:
- { name: doctrine.event_listener, event: postConnect }
I don't know about Symfony/Doctrine, but this is simple to fix with the regular OCI functions:
$conn = oci_connect('username', 'password', 'connection_string');
// get the sysdate...
$select = oci_parse($conn, 'select sysdate from dual');
oci_execute($select);
print_r(oci_fetch_row($select));
// alter the session date format...
$alter = oci_parse($conn, 'alter session set NLS_DATE_FORMAT=\'YYYY-MM-DD HH24:MI:SS\'');
oci_execute($alter);
// get the sysdate again...
oci_execute($select);
print_r(oci_fetch_row($select));
This gives the output:
Array
(
[0] => 10-JUN-16
)
Array
(
[0] => 2016-06-10 13:39:34
)

How to format date fields before save in CakePHP 3?

I used this in AppController:
Time::setToStringFormat('dd/MM/YYYY');
The date field in my form is a input type "text" to allow my user writes something like 31/12/2015.
However when I try to save (MySQL date) I get some errors of Time Class because inside the table the value now is 00-00-0000
Alunos Controller code
Thanks !
My final solution was this on bootstrap:
date_default_timezone_set('America/Sao_Paulo');
setlocale(LC_ALL, 'pt_BR', 'pt_BR.utf-8', 'pt_BR.utf-8', 'portuguese');
Type::build('time')->useImmutable();
Type::build('date')->useImmutable()->useLocaleParser();
Type::build('datetime')->useImmutable()->useLocaleParser();
Type::build('timestamp')->useImmutable();
\Cake\I18n\Time::setToStringFormat('dd/MM/yyyy HH:mm:ss');
\Cake\I18n\Date::setToStringFormat('dd/MM/yyyy');
\Cake\I18n\FrozenTime::setToStringFormat('dd/MM/yyyy HH:mm:ss');
\Cake\I18n\FrozenDate::setToStringFormat('dd/MM/yyyy');
\Cake\I18n\I18n::locale('pt-BR'); //new !
Type::build('decimal')->useLocaleParser();
Type::build('float')->useLocaleParser();
maybe this could help someone.
public function beforeSave($event, $entity, $options) {
$entity->dateField = date('Y-m-d', strtotime($entity->dateField));
}
If you are just creating a new application with a fresh database, delete does dates having 0000-00-00 and change the column definition so it can accept nulls. Using 0000-00-00 for dates is usually a really bad thing as only errors and bugs can come out of it :)
Edit based on the comments below
It seems like the problem was getting a string field to be parsed from the local date format to what php can understand. For this task you just need to configure the DateTimeType class to parse the dates using a locale-aware format as described here http://book.cakephp.org/3.0/en/orm/database-basics.html#parsing-localized-datetime-data
// In bootstrap.php or AppController or your controller action:
use Cake\Database\Type;
...
Type::build('datetime')->useLocaleParser();
You can also set the locale parser to parse a specific format. For the code above to work, make sure you set your application to use a locale:
I18n::locale('fr-FR')
Easy solution insert date format in CakePHP 3.x in Models and custom out views:
Insert ['rule' => ['date','dmy']]
Example
public function validationDefault(Validator $validator)
{
...
$validator
->add('demo_example_date', 'valid', ['rule' => ['date','dmy']]) //Format valid '30-12-2015' or '30-12-05'
->requirePresence('demo_example_date', 'create')
->notEmpty('factura_fecha');
...
return $validator;
}
Out view, set AppController
...
use Cake\I18n\Time;
use Cake\Database\Type;
Time::$defaultLocale = 'es-ES';
Time::setToStringFormat('dd-MM-YYYY');
Type::build('datetime')->useLocaleParser();
class AppController extends Controller
{
...
}
works for me using Postgres.
File config/app.php
in variable Datasources['default'] add command 'SET datestyle TO ISO, DMY' to init
'Datasources' => [
'default' => [
'init' => ['SET datestyle TO ISO, DMY '],
],
in mysql
https://my.vertica.com/docs/7.1.x/HTML/Content/Authoring/SQLReferenceManual/Statements/SET/SETDATESTYLE.htm

Zend framework 2 - How to make a language switcher

I am developing a Zend Framework 2 Application and now I want to implement a language switcher from where guest/registered user can choose the language they want, the thing I can't understand is how is it made in Zend Framework 2 using the storage ( not from urls ), I want to keep the preffered language of guest in the storage once he selects one, and for the registered users I can retrieve the preffered one from cookie/database and reuse it with storage. But where and how should I start/implement this?
Thank you in advance.
Setup your Locales in your global.config.php:
'locale' => array(
'default' => 'en_US',
'available' => array(
'de_DE' => 'Deutsch',
'nl_NL' => 'Dutch',
'en_US' => 'English',
'fr_FR' => 'French',
),
),
So in your Application\Module.php you can add a method which sets the default Zend\Translator\Translator:
class Module {
public function onBootstrap(MvcEvent $e)
{
$applicaton = $e->getApplication();
$serviceManager = $application->getServiceManager();
// Just a call to the translator, nothing special!
$serviceManager->get('translator');
$this->initTranslator($e);
// Etc, more of your bootstrap function.
}
protected function initTranslator(MvcEvent $event)
{
$serviceManager = $event->getApplication()->getServiceManager();
// Zend\Session\Container
$session = New Container('language');
$translator = $serviceManager->get('translator');
$translator
->setLocale($session->language)
->setFallbackLocale('en_US');
}
}
So now the default Locale is en_US as the session has no Locale available. For changing the locale you need to catch the users input and validate the available locales you support, provided in your global.config.php. So in order to change it you might need to add a controller action which catches the input of the user and sets the new locale. Example of the controller action without any form usage!
public function changeLocaleAction()
{
// New Container will get he Language Session if the SessionManager already knows the language session.
$session = new Container('language');
$language = $this->getRequest()->getPost()->language;
$config = $this->serviceLocator->get('config');
if (isset($config['locale']['available'][$language]) {
$session->language = $language;
$this->serviceLocator->get('translator')->setLocale($session->language);
}
}
The session allows the users to change their locale and remember it until the session ends, so they won't need to change it when they get back after a while. Hope this will help you and can help you to write some code to save it for your registered users on your application.
I am not sure, my approach will work or not. Please try:
We can have 3 params for translate method.
$translator->translate($message, $textDomain, $locale);
The $locale parameter is taken from the locale, set in the translator and that's why we usually not set manually in the code. So, you can use like below :
$localeVar = 'de_DE'; OR $localeVar = 'en_US'; // according to user's selection
echo $this->translate("Translate me", $textDomain, $localeVar);
You can have a key value pair - key can be user selected language and value can be any one of the language.
array(
'english' => 'en_US',
'deutch' => 'de_DE',
'frecnh' => 'fr_FR',
// other language
);

ZF2 Currency Format

I am using ZF2 for my project. And this is an e-commerce site. So I am dealing with currencies.
In ZF2 there is a view helper named currencyFormat()
I am from Turkey so my main currency format is TRY (This is the ISO code of Turkish Lira). But in Turkey we do not use TRY as Currency icon. The icons are "$" for USD, € for "EUR" and "TL" for Turkish Lira (TRY).
So when I format a currency for TRY I am doing it like this in view script:
<?php
echo $this->currencyFormat(245.40, 'TRY', 'tr_TR');
?>
The result of this code is "245.40 TRY". But it has to be "245.40 TL"
Is there a way to solve this? I do not want to use replacement function.
I'm guessing when you say I do not want to use replacement function you mean it would be laborious to do a str_replace every time you call the helper. The solution would be to replace the helper with your own. Here's a quick how to
First create a helper of your own which extends the existing helper and handles the replacement if necessary...
<?php
namespace Application\View\Helper;
use Zend\I18n\View\Helper\CurrencyFormat;
class MyCurrencyFormat extends CurrencyFormat
{
public function __invoke(
$number,
$currencyCode = null,
$showDecimals = null,
$locale = null
) {
// call parent and get the string
$string = parent::__invoke($number, $currencyCode, $showDecimals, $locale);
// format to taste and return
if (FALSE !== strpos($string, 'TRY')) {
$string = str_replace('TRY', 'TL', $string);
}
return $string;
}
}
Then in Module.php, implement the ViewHelperProviderInterface, and provide it with details of your helper
//Application/Module.php
class Module implements \Zend\ModuleManager\Feature\ViewHelperProviderInterface
{
public function getViewHelperConfig()
{
return array(
'invokables' => array(
// you can either alias it by a different name, and call that, eg $this->mycurrencyformat(...)
'mycurrencyformat' => 'Application\View\Helper\MyCurrencyFormat',
// or if you want to ALWAYS use your version of the helper, replace the above line with the one below,
//and all existing calls to $this->currencyformat(...) in your views will be using your version
// 'currencyformat' => 'Application\View\Helper\MyCurrencyFormat',
),
);
}
}
As of 1 March 2012 sign for Turkish Lira is TRY. http://en.wikipedia.org/wiki/Turkish_lira
So ZF outputs it right I think.

Categories