I have been trying to figure out another way of handling i18n within FuelPHP (see here).
I decided to import the Symfony2 Translation component (using composer) to Fuel as a vendor and manage i18n with xliff files.
Here is my (simplified) code:
use \Symfony\Component\Translation\Translator;
use \Symfony\Component\Translation\MessageSelector;
use \Symfony\Component\Translation\Loader\XliffFileLoader;
...
class I18N
{
private static $translator = NULL;
....
public static function get($key)
{
# Load and configure the translator
self::$translator = new Translator('en_GB', new MessageSelector());
self::$translator->addLoader('xliff', new XliffFileLoader());
self::$translator->addResource('xliff', 'path/to/xliff/file', 'en');
# Get the translation
$translation = self::$translator->trans($key, $params);
# Return the translation
return $translation;
}
}
So at first I thought that was working great since I was testing it on a very small xliff file but now that I've generated the complete xliff catalogue (about 1400 entries) for my entire application, each request is really slow.
So the question is, is there a way to cache translations when using the Translation component the same way the whole Symfony2 Framework caches it natively?
The Translator Class from the FrameworkBundle has a constructor that accepts options in which you can define the cache_dir. Anyway I can achieve that using the Translation component?
Thanks for any help on that matter.
So what I did was to generate my own cache from xliff files, if it doesn't exist, which is nothing more than the translations as a php array and make the Translator Component load resources as ArrayLoader instead of XliffFileLoader. It's lightning fast now. Thanks to Touki in the comments for your interest.
Related
I need to integrate Slider Revolution editor into my Laravel (5.5) app.
I've put the editor in public/revslider/ folder to be able to use the visual editor. I also created a helper class to "communicate" with it and be able to use it inside my Blade views:
namespace App\Helpers;
include( public_path('revslider/embed.php') );
class Slider{
/**
* This function is called where you want to put your slider
*/
public static function make($slider){
return \RevSliderEmbedder::putRevSlider( $slider );
}
/**
* This function is called inside <HEAD> tag to include all
* SR assets (js/css/font files)
*/
public static function head(){
return \RevSliderEmbedder::headIncludes(false);
}
}
The SR's PHP code does not use namespaces. In fact it is a strange mix of Code Igniter, Wordpress and vanilla php.
The problem is it is trying to declare a translation function __(...):
if( ! function_exists('__'))
{
function __($string = '')
{
....
}
}
and since there is already such Laravel's helper function, it does not redeclare it and tries to use Laravel's __() function. And that obviously causes errors.
I temporarily managed to fix this problem by changing the name of SR's __() function (and all references to it). But of course it is not a best way to solve this problem, since I will be unable to use SR's automatic updates or will be forced to do these changes after every update.
So my questions are:
Is there any good way of integrating such "bad" code into your project, invoking it safely without conflicts? Is there any way of isolating such code and avoid clashes? By "bad code" I mean code that does not follow strict OOP/PSR rules present in projects like Laravel.
What is the best way to include "external" PHP code? I've just used plain include() inside of my helper class' file, but is there a better/cleaner way? Like, I don't know, loading it through composer?
I spend quite some time trying to figure out how to "compile" all my Twig templates in a Slim based application, to make sure all strings were ready to be picked up by xgettext for further processing and translation.
It turned out to be quite easy as soon as I had the right pieces of information put together, but I couldn't find any place on the internet telling me how to do exactly this with Twig in a Slim application.
The Twig documentation has a fine example of how to extract template strings. However, before you're able to do that, you need to pull the Twig environment out of your Slim application, as described in the Slim Knowledge Base.
So, here's a modified version of the example from Twig documentation:
// Specify where your templates are located.
$tplDir = '/path/to/your/templates';
// Get the Twig environment from your Slim app, $app.
$twig = $app->view()->getEnvironment();
// Iterate over all your templates.
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tplDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file)
{
// Force compilation.
if ($file->isFile()) {
$twig->loadTemplate(str_replace($tplDir.'/', '', $file));
}
}
What I am trying to achieve is urls outputting via pagination like this:
http://www.mysite.com/users/page5
or
http://www.mysite.com/users/page-5
At present, it will be using the URI segments like this:
http://www.mysite.com/users/page/5
I can modify the routes.php config file to route the path if the first two URLs are used. So, that's not the issue.
What I am having trouble with is, how do I initialize the settings for the pagination, so that the $this->pagination->create_links() will create a pagination with items having links like in the first or the second format?
Let me know if you need more explanation or examples regarding this. I'm not much good in explaining things. :)
Thank you
This functionality already exists in the in-development version of CodeIgniter 3.0. You can view the Pagination class as it sits here.
To use this library, you can either A) use all of CI 3.0 (it's pretty stable), or B) extend (or, more realistically, replace) the Pagination library by creating application/libraries/MY_Pagination.php and filling it with the contents of the link above. (Full disclosure: it's been a while since I tinkered with CI, so I don't know if anything has changed since that may result in errors with any of this answer.)
To use the feature you want, specify your base URL minus the page-X segment, set that you want to use page numbers instead of offset in your URI segment, and then specify a prefix.
$config['base_url'] = site_url('users');
$config['use_page_numbers'] = true;
$config['prefix'] = 'page-';
Make sure to include your other obvious items as well, such as per_page, etc.
To change the functionality of the Pagination library, you can extend the library and override the create_links() function.
Create a file named MY_Pagination.php in application/libraries/
The file should have the following structure, so you can change or add additional functionality to CI's native Pagination library. (It is bad practice to directly change the Pagination library in the system directory.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Pagination extends CI_Pagination {
public function __construct()
{
parent::__construct();
}
}
You'll then need to add the create_links() function to your MY_Pagination class, allowing you to override its default functionality. Below is an explanation of what you could change to achieve your desired output (you may want to add flexibility, by adding a parameter to the function, but this is the simplest change that I could think of.)
function create_links()
{
// You can copy the exact functionality of this function from:
// system/libraries/Pagination.php
// The line you want to change is:
// $this->base_url = rtrim($this->base_url, '/') .'/';
// Changing to this: $this->base_url = rtrim($this->base_url, '/') .'';
// Will create links in this format: ../page5
// Or changing to this: $this->base_url = rtrim($this->base_url, '/') .'-';
// Will create links in this format: ../page-5
}
I converted our Meteor site to support two languages, Dutch and English. To do this I made two folders for our templates (en and nl) and hooked everything up to our templating system so the router serves things correctly depending on which site you're on. The main body template is dynamic:
Template.body.content = function() {
var lang = Session.get("lang") == "en" ? "en_" : "";
var page = Session.get("page") || "home";
// if the template for the current language doesn't exist,
// fall back to Dutch version or show a 404
var template = Template[lang + page] || Template[page] || Template[lang + "error404"];
return template();
}
Everything works pretty well except that I have to write the following to expose a template value to both languages:
Template.en_foo.bar = Template.foo.bar = function() {}
For an example of this code as used in production, see our client-side blog code.
What's an elegant way to avoid this approach while still accomplishing the goal of a multilingual site?
What about this:
make a custom subscription and pass the language argument to a custom publish
the custom publish function returns only the selected language (optionally you can provide fallbacks if content is unavailable)
use just one template for all languages, filled with the right language from the subscription
use i18n package for the UI strings
Multi-languages applications is on the Meteor roadmap but it's planned in a long time...
Meanwhile you can use this atmosphere package.
I'd recommend heavily against keeping translated versions of your templates around. Unless your site is tiny. It might not seem so bad at first because you just copy them and translate the contents. But from then on you'll have to maintain both versions on any change, test both. And then somebody will suggest adding that third language and boom, triple damage to your brain.
We're using meteor-messageformat for translations. It comes with an interface that allows creating translations without having to look at template code. Anybody can translate.
At work I've been asked to make a small web based mini-game prototype.
I went down the flash route and am using Flash Develop with Flex SDK.
I've also found a graphical framework and I can use that no problem, but I'm trying to make my own code reusable at a later date.
I have written a small class for loading a list of textures, from names supplied to the class before loading. It is here to keep the question concise.
To be honest when it comes to Flash/ActionScript, I have no idea what I'm doing, I only started using it a week ago.
What I want to know is whether my attempt is acceptable from a more experienced AS programmer's point of view. Is it really bad flash coding practice? Does flash handle garbage collection? Should I be keeping an eye on the new Loader() calls that I just disregard?
First of all make loader as field of your class and reuse it. Then add error listener:
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
Also you should check input data:
public function addImage(fname:String):void {
if(fname && fname != "") array.push(fname);
}
When all images were loaded you should "reset" you loader:
array = [];
And it would be better if you will check the state of your loader to prevent unpredictable cases:
public function beginLoad():void {
if(state == ALREADY_LOADING) return;
count = 0;
loadImages(count);
}
ps immutable fields such as loader, map, array mark const. It's not mistake but other developers will know that these fields are immutable.