ZF2 Translation inside autoload dictionaries - dictionary

I've got a ZF2 project with basic/skeleton structure. I've got /var/www/project/module/Application/language with a languages and
/var/www/project/config/autoload/dictionaries.php which contain month names and so on.
I need to translate values of dictionary to desired language. I have tried to make it the same way as I did inside View /var/www/project/module/Application/view/application/module-name/×××.phtml:
$this->plugin('translate')->getTranslator()->setLocale('en_US');
$this->translate("foreign language staff");
But $this have no idea what I'm talking about. Then I try the way I try it inside Controllers /var/www/project/module/Application/src/Application/Controller/ModuleController.php:
use Zend\I18n\Translator\Translator;
class CompanyController extends AbstractActionController {
public function indexAction() {
$translator = new \Zend\I18n\Translator\Translator;
define('LOCALE', substr($translator->getLocale(),0,5));
$translator->setLocale(LOCALE);
$translator->addTranslationFile('gettext', '/....../language/' . LOCALE . '.mo', 'messages', LOCALE);
$translator->translate("foreign language staff"),
But no in the dictionary neither in Controller I can not get translate, even addTranslationFile file path and LOCALE is correctly settled.

Related

Symfony 2 get Sonata media file path in Entity class

When implementing a __clone() method in media entity, I need to get the absolute path of a file to be able to make a copy of the file itself. I've been searching for a long time and I have not found any documentation to get this. Any ideas?
Here it is the __clone() method where I need the file path:
// Norwalk\StoreBundle\Entity\ProductHasMedia
public function __clone() {
if ($this->id) {
$this->media = clone $this->media;
$this->media->setProviderReference('clone_'.$this->media->getProviderReference());
$this->media->setName('clone_'.$this->media->getName());
$providerMeta = array('filename' => $this->media->getName());
$this->media->setProviderMetadata($providerMeta);
// Clone the physical image file too
$fs = new Filesystem();
$fs->copy( "original_image_path/".$this->media->getName(), "original_image_path/"."clone_".$this->media->getName());
}
}
I don't think it is possible without giving the Entity class to much responsibilities since you can't tell the absolute path name without having some services ('sonata.media.manager.media', 'sonata.media.provider.image' or 'sonata.media.twig.extension')..
The proper way to go is to build a clone function into an controller. The controller can have all the magic (services and entitymanagers) to do the cloning for you.
See this stackoverflow question for an example.

getting the gettext behavior using the Po File Loader in the translation provider in Silex

I'm using the translation provider and the PoFileLoader in Silex and everything works super great.
$app['translator'] = $app->share($app->extend('translator', function($translator, $app) {
$translator->addLoader('po', new PoFileLoader());
$translator->addResource('po', __DIR__.'/resources/translations/de.po', 'de');
}
The only problem that I have is how it treats strings that doesn't have translation yet. I want them to be ignored and use the source instead of an empty string. Like the way gettext function treats the po files.
Is there any option for that or should I override the PoFileLoader class?
The only problem that I have is how it treats strings that doesn't have translation yet. I want them to be ignored and use the source instead of an empty string. Like the way gettext function treats the po files.
This is something the translator does, not the file loader. If there is no translation found in the message catalogue, the translator will just replace the parameters and return the source.
See also the source:
public function get($id, $domain = 'messages')
{
// ... all the loading logic
// if everything failed, just return the source
return $id;
}
This method is called in the Translator#trans method.

Dynamic data-driven website localization

I have a website that reads some of its content from a database, I need this website in both languages, English and Arabic.
the needed content is duplicated in the database in both languages. lets say I have a En_Name and Ar_Name columns in my database.
and for example for the Arabic version of the website a link will display a text from Ar_Name , and with the English one it should display the text from the En_Name.
for the static content in my website I think it is a good idea to use the ASP.NET default localization using (.resx files). but what I don't know is how to do the localization for the dynamic section of the website.
So, how can I make the same hyperlink read once from the Ar_Name field, and then from the En_Name based on the users choice (Localization)?
There are many ways to accomplish this. You've not mentioned which database technology you are using, so my example is with Entity Framework. You may need to customise this to your own situation.
Something similar may be possible with LinqToSql or other ORMs. If you are using something else entirely, then the key is to have a central class that you pass something consistent to (hence the interface) that does the translation.
For example, if I was using Entity Framework, every table in the database that had these two fields I'd add an interface that exposes those fields. Then I'd have a helper class with a method that took any entity with that interface and checked the current localisation and return the correct version of the text.
public interface IBilingualEntity
{
// Defines a consistent interface that indicates which language version
// each thing is in.
string Ar_Name { get; }
string En_Name { get; }
}
public partial MyEntity : IBilingualEntity
{
// This is a class generate by Entity Framework. But it could
// be anything really if you are using some other framework.
//
// Nothing to do here as the other side of the partial
// should already implement the interface with the code
// generated from Entity Framework. If not, implement the
// interface and return the correct language version in
// the property.
}
// This is the helper that works out which language version to use.
public class BilingualHelper
{
public string GetName(IBilingualEntity entity)
{
// NOTE: You may have to strip away the region part of the name
// but off the top of my head I can't remember the format.
// If you are using something else to store the culture you'll
// have to reference that instead.
var cultureName = Thread.CurrentThread.CurrentUICulture.Name;
if (cultureName == "ar")
return entity.Ar_Name;
return entity.En_Name;
}
}

Symfony2 Sluggable multiple separators

Using the Gedmo Sluggable behavior in Symfony2, I need to know if there is a way to allow both slashes (/) and dashes (-) as word separators. In other words, one specific separator as usual, but leaving alone the other specific special character so it is ignored. I want to do something like this as a slug:
products/some-product
This allows me to use slugs in the URL that are categorized via the slash and separate the spaces via the dash. But, for instance, if the separator is "/", the "-" will be replaced as well instead of left alone.
I've looked through the related Sluggable class code (Urlizer) and see a lot of regex going on, but I'm not sure where I should override to allow slashed and/or dashes to NOT be substituted along with everything else.
Turns out you can accomplish this by creating your own class that extends Urlizer, then setting it as the callable for the listener instead of Gedmo's class.
When using STOF doctrine extensions, a sluggable listener is created as a service, but it is set as private so you can't normally access. So you must first create an alias to this listener in your own config:
services:
sluggable.listener:
alias: stof_doctrine_extensions.listener.sluggable
You must then create your class. There is a setter called setTransliterator() that you can use to call your own transliterator, which you can then use to inject what you need to modify the slugging process. The function postProccessText() is what you really want to modify, the transliterate() function is just what is callable:
namespace My\Bundle\Util;
use Gedmo\Sluggable\Util\Urlizer as BaseUrlizer;
class Urlizer extends BaseUrlizer
{
public static function transliterate($text, $separator = '-')
{
// copy the code from the parent here
}
private static function postProcessText($text, $separator)
{
// copy code from parent, but modify the following part:
$text = strtolower(preg_replace('/[^A-Z^a-z^0-9^\/]+/', $separator,
preg_replace('/([a-z\d])([A-Z])/', '\1_\2',
preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2',
preg_replace('/::/', '/', $text)))));
}
}
The regular expressions of postProcessText() are what you want to modify to your liking. After that, you must make your function the callable right before you persist, and you're good to go:
// custom transliterator
$listener = $this->get('sluggable.listener');
$listener->setTransliterator(array('My\Bundle\Util\Urlizer', 'transliterate'));
$em->flush();

Best way for extending a entity in doctrine

I have a User Entity in a small Framework made by me. Now i want to use this User Entity in several projects.
But in some projects I want to add a few fields to the User Entity without modifying the file.
What I tried so far:
I created a new DefaultUser Entity in a DefaultUser Bundle and made the User Entity a mappedsuperclass. But now I can't make a association in other entities like
/*
* #ORM\ManyToOne(targetEntity="User", inversedBy="jobs")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
private $user;
Because Doctrine can't find the id column in the user entity. This only works if I specify the DefaultUser Entity. According to the doctrine documentation this only works on many to many associations if only one leaf exists.
Then I tried Single Table Inheritance. This works fine but I have to modify the DiscriminatorMap if I want to extend my user entity which is shared acros multiple projects...
So whats the best way to extend the UserEntity?
I have precisely the same problem - I have just switched from RedBean to Doctrine (for a project using the Zend Framework), and the structure of my classes did not take into account this issue. The core problem is that maps in Doctrine have a one to one relationship with classes, as far as I can work out. What we are looking for is a way to have one concrete class (the UserEntity) that uses a map from an abstract class (the DefaultUser). My solution, which may be something of a hack (I've only been using Doctrine for a couple of days), works for YAML at least:
Create a new mapping driver extending the YAML driver, and override the _loadMappingFile method with something like this:
class MyLibrary_Doctrine_Mapping_Driver_YamlExtended extends MyLibrary_Doctrine_Mapping_Driver_YamlExtended
{
protected $_basicEntityFolder;
protected function _loadMappingFile($file)
{
$entMaps = parent::_loadMappingFile($file);
//merge this with any extensions if defined
foreach($entMaps as $ent => $map)
{ //load the relevant map
if (!isset($map['extendEntity'])) {
continue;
}
$fileName = $this->_basicEntityFolder . DIRECTORY_SEPARATOR . str_replace('\\', '.', $map['extendEntity']) . $this->_fileExtension;
$extendedMaps = $this->_loadMappingFile($fileName);
if (!is_array($extendedMaps[$map['extendEntity']])) {
throw new MyProject_Doctrine_Exception("Entity to extend from could not be found.");
}
//merge so that the file lower in the class hierachy always overrides the higher
$map = array_merge($extendedMaps[$map['extendEntity']], $map);
//clear the extendEntity value
unset($map['extendEntity']);
$entMaps[$ent] = $map;
}
return $entMaps;
}
public function setExtendedEntitiesFolder($path)
{
$this->_basicEntityFolder = $path;
}
}
I then have two yaml files, in different folders, like this:
#MyApplication/Entities/Maps/Entities.User.dcm.yml
Entities\User:
extendEntity: LibraryEntities\User
That is the file in the application. Then in the library I have
#Library/Entities/Maps/ExtendedEntities/LibraryEntities.User.dcm.yml
LibraryEntities\User:
type: entity
table: user
fields:
username:
type: text
nullable: true
password:
type: text
nullable: true
defaultProfile:
type: text
nullable: true
column: default_profile
The reason it is in an ExtendedEntities folder is so I can define mappedSuperclasses in the library using a normal namespace, and Doctrine will load those automatically when a class extends them, but these extendedentities are outside of the path for Doctrine's usual class inheritance loading (if they were all in the normal folder structure then for eg "class ApplicationUser extends LibraryUser" Doctrine would try to load the config for LibraryUser because it would find it, and then cause the same error you have already encountered).
Then when I set up my $em I provide it with my driver:
$driverImpl = new MyLibrary_Doctrine_Mapping_Driver_YamlExtended(array(APPLICATION_PATH . '/entities/maps',
LIBRARY_PATH . '/Entities/Maps'));
$driverImpl->setExtendedEntitiesFolder(LIBRARY_PATH . '/Entities/Maps/ExtendedEntities');
Notice that this solution allows inheritance chains defined by 'extendEntity' (because the _loadMappingFile method is recursive). Also that any configuration file lower down the chain can overwrite any property already defined, so even if in your library yaml you had:
username:
type: text
Say you had a project in which usernames where integers you can simply override it in your application config with
username:
type: int
or whatever.
And therefore this solves the problem of defining Doctrine style inheritance on the base class. In every project you can define the DiscriminatorMap however you like.
In principle the same solution could be applied to annotations, though extending the annotation driver is a little more complicated, because it doesn't simply read metadata by reading one file in one go and converting it to an array, but makes numerous requests to the annotation reader, which means implementing this structure would be trickier.
I'd be very interested to know how other people have solved this problem.

Resources