Polyglot seems not working when using translate function - admin-on-rest

The transalte's polyglot feature don't work (i'm in the last version of react-admin) :
this my language file :
export default
{
"labels": {
"num_files": "%{count} file |||| %{count} files"
}
}
and how i call the tranlate function :
translate('labels.num_files', { count: 5 })
and it's shown in my component :
5 file |||| 5 files

According to Polyglot documentation, the variable which should be used to determine whether to use the singular or plural form must be named smart_count.
This is because you may have multiple variables and polyglot needs to which one to use for pluralization detection.

Related

How to minify view HTML in Codeigniter 4 (CI 4)

I know we can minify HTML in CI3 through the hook but in CI 4
I have done it by adding a minify function before return on every method.
minifyHTML(view('admin/template/template',$this->data));
Any other way I can do it without using the minify function everywhere?
I also figure out another solution which is to add a template function in BaseConroller which renders all the views. but I have already used view() in many places in the project and its not feasible for me but can be work for others.
In CodeIgniter4 You can use Events to Minify the output (Instead of using Hooks like what we did in CodeIgniter3) , by adding the following code inti app/Config/Events.php file
//minify html output on codeigniter 4 in production environment
Events::on('post_controller_constructor', function () {
if (ENVIRONMENT !== 'testing') {
while (ob_get_level() > 0)
{
ob_end_flush();
}
ob_start(function ($buffer) {
$search = array(
'/\n/', // replace end of line by a <del>space</del> nothing , if you want space make it down ' ' instead of ''
'/\>[^\S ]+/s', // strip whitespaces after tags, except space
'/[^\S ]+\</s', // strip whitespaces before tags, except space
'/(\s)+/s', // shorten multiple whitespace sequences
'/<!--(.|\s)*?-->/' //remove HTML comments
);
$replace = array(
'',
'>',
'<',
'\\1',
''
);
$buffer = preg_replace($search, $replace, $buffer);
return $buffer;
});
}
});
see https://gitlab.irbidnet.com/-/snippets/3
You need the extend your core system classes to be able to do that in a system wide scope.
Every time CodeIgniter runs there are several base classes that are initialized automatically as part of the core framework. It is possible, however, to swap any of the core system classes with your own version or even just extend the core versions.
Two of the classes that you can extend are these two:
CodeIgniter\View\View
CodeIgniter\View\Escaper
For example, if you have a new App\Libraries\View class that you would like to use in place of the core system class, you would create your class like this:
The class declaration must extend the parent class.
<?php namespace App\Libraries;
use CodeIgniter\View\View as View;
class View implements View
{
public function __construct()
{
parent::__construct();
}
}
Any functions in your class that are named identically to the methods in the parent class will be used instead of the native ones (this is known as “method overriding”). This allows you to substantially alter the CodeIgniter core.
So in this case you can look at your system view class and just change it to return the output already compressed.
In your case You might even add an extra param so that the view function can return the output either compressed or not.
For more information about extending core classes in CodeIgniter 4 read this:
https://codeigniter.com/user_guide/extending/core_classes.html#extending-core-classes
In CodeIgniter 4, you can minify the HTML output of your views by using the built-in output compression library.
First, you need to enable output compression in your application's configuration file, which is located at app/Config/App.php.
Then, you need to set the compression level. You can set the compression level by changing the value of compress_output option. The possible values are:
0 : Off (Do not compress the output)
1 : On (Compress output, but do
not remove whitespace)
2 : On (Compress output, and remove
whitespace)
Finally, you need to load the Output Library in your controller, before the output is sent to the browser. You can load it using the following line of code:
$this->load->library('output');

Text direction and pluralization dataset

I am working on a Ruby on Rails project, in which I need to get the text direction and the plural form for different languages. Something like:
en: { plural_keys: [:one, :other], text_dir: :left_to_right },
sk: { plural_keys: [:one, :few, :other], text_dir: :left_to_right },
...
Is there any free dataset I could extract this information from?
I have found CLDR - Unicode Common Locale Data Repository which contains all data I need. It is also available as the twitter_cldr gem.

Yii2 change locale formats

I am migrating from Yii 1.x to Yii2.
In Yii 1.x you could define/change the localized formats in a file (sth like /app/i18n/en.php), where you could set all your desired formats, which you could later use.
Now in Yii2 this is gone?
I have 4 languages, each one has different settings. What am i supposed to do if I need a new formatting function?
E.g. I want to make a format for prices in a shop, in each lang differently
DE - 1.234,56
EN - 1,234.567
SK - 1234,5
CZ - 1 234,5678
So I create a new formatter function Yii::$app->formatter->asPrice(1234.567890).
Do I have to program a switch inside the function, and check for the language? That would be very inconvenient, and a lot of duplicity if I need more such functions. And if I had a new language later, I would have to adjust all such functions with a new case.
There must be a better solution. Any ideas?
UPDATE
I think you guys did not get my problem.. I know I can set the locale, and use the asDecimal or similar function. But the problem is that I cannot specifically customize the formatting options - it automatically takes the format defined in the intl PHP extension. I need the possiblity to specifically customize these formats. Maybe e.g. the default for EN is 2 decimals, but I need 3. Where can I set this?
In Yii2 official documentation:
You can use as below:
Yii::$app->formatter->locale = 'en-US';
echo Yii::$app->formatter->asDate('2014-01-01'); // output: January 1, 2014
Yii::$app->formatter->locale = 'de-DE';
echo Yii::$app->formatter->asDate('2014-01-01'); // output: 1. Januar 2014
Yii::$app->formatter->locale = 'ru-RU';
echo Yii::$app->formatter->asDate('2014-01-01'); // output: 1 января 2014 г.
So if you have table with language you can set locale there and in main layout define "Yii::$app->formatter->locale = $lang->locale" where $lang is object of Language model(class) matching current language.
Why dont you want to use asDecimal?
echo Yii::$app->formatter->asDecimal(1234.5678);
DE - 1.234,568
EN - 1,234.568
SK - 1 234,568
CZ - 1 234,568
Or you may try something like:
private $_priceDecimals = [ 'de_DE' => 2, 'en_EN' => 3, 'sk_SK' => 1, 'cz_CZ' => 4];
public function asPrice($value)
{
return $this->asDecimal(
$value,
isset($this->_priceDecimals[$this->locale]) ? $this->_priceDecimals[$this->locale] : null
);
}

mustache/hogan i18n and taking word-order into account

Found a couple of questions (and answers) on this: How is internationalization configured for Hogan.js?
,etc.
but non in particular that take word order into account. I need the ability to:
step 1. given a key -> lookup a sentence in a particular language.
step 2. this sentence may contain {{var}} , which need to be
substituted by json-values.
step 2. alone is general mustache-templating.
step 1. alone could be done with several techniques, but I prefer techniques that don't involve any specialized code outside of the Mustache/Hogan engine (in combination with a i18n-resource bundle of course) . Hogan seems to support this with something like: (from url above)
var template = "{{#i18n}}Name{{/i18n}}: {{username}}",
context = {
username: "Jean Luc",
i18n: function (i18nKey) {return translatedStrings[i18nKey];}
};
However to combine 1. and 2. in this example I would want translatedStrings[i18nKey] to return a string which potentially contains {{<some expansion>}} as well.
Someone knows of an elegant way to do this?
Rationale:
Often languages differ a lot in word order, etc. which makes for complex templates without this ability.
The latest version of Hogan.js will handle Mustache tags inside the result returned from a lambda. One minor change to the code in your question however, is that the result of the lambda should be a function in order to modify the string:
var translatedStrings = { name: "Nom {{rank}}" };
var template = "{{#i18n}}name{{/i18n}}: {{username}}",
context = {
username: "Jean Luc",
rank: 'Captain',
i18n: function() {
return function (i18nKey) {return translatedStrings[i18nKey];};
}
};
document.write(Hogan.compile(template).render(context));​ // Nom Captain: Jean Luc
I created a jsfiddle that demonstrates this with the latest version.

How to make client side I18n with mustache.js

i have some static html files and want to change the static text inside with client side modification through mustache.js.
it seems that this was possible Twitter's mustache extension on github: https://github.com/bcherry/mustache.js
But lately the specific I18n extension has been removed or changed.
I imagine a solution where http:/server/static.html?lang=en loads mustache.js and a language JSON file based on the lang param data_en.json.
Then mustache replaces the {{tags}} with the data sent.
Can someone give me an example how to do this?
You can use lambdas along with some library like i18next or something else.
{{#i18n}}greeting{{/i18n}} {{name}}
And the data passed:
{
name: 'Mike',
i18n: function() {
return function(text, render) {
return render(i18n.t(text));
};
}
}
This solved the problem for me
I don't think Silent's answer really solves/explains the problem.
The real issue is you need to run Mustache twice (or use something else and then Mustache).
That is most i18n works as two step process like the following:
Render the i18n text with the given variables.
Render the HTML with the post rendered i18n text.
Option 1: Use Mustache partials
<p>{{> i18n.title}}</p>
{{#somelist}}{{> i18n.item}}{{/somelist}}
The data given to this mustache template might be:
{
"amount" : 10,
"somelist" : [ "description" : "poop" ]
}
Then you would store all your i18n templates/messages as a massive JSON object of mustache templates on the server:
Below is the "en" translations:
{
"title" : "You have {{amount}} fart(s) left",
"item" : "Smells like {{description}}"
}
Now there is a rather big problem with this approach in that Mustache has no logic so handling things like pluralization gets messy.
The other issue is that performance might be bad doing so many partial loads (maybe not).
Option 2: Let the Server's i18n do the work.
Another option is to let the server do the first pass of expansion (step 1).
Java does have lots of options for i18n expansion I assume other languages do as well.
Whats rather annoying about this solution is that you will have to load your model twice. Once with the regular model and second time with the expanded i18n templates. This is rather annoying as you will have to know exactly which i18n expansions/templates to expand and put in the model (otherwise you would have to expand all the i18n templates). In other words your going to get some nice violations of DRY.
One way around the previous problem is pre-processing the mustache templates.
My answer is based on developingo's. He's answer is very great I'll just add the possibility to use mustache tags in the message keycode. It is really needed if you want to be able the get messages according to the current mustache state or in loops
It's base on a simple double rendering
info.i18n = function(){
return function(text, render){
var code = render(text); //Render first to get all variable name codes set
var value = i18n.t(code)
return render(value); //then render the messages
}
}
Thus performances aren't hit because of mustache operating on a very small string.
Here a little example :
Json data :
array :
[
{ name : "banana"},
{ name : "cucomber" }
]
Mustache template :
{{#array}}
{{#i18n}}description_{{name}}{{/i18n}}
{{/array}}
Messages
description_banana = "{{name}} is yellow"
description_cucomber = "{{name}} is green"
The result is :
banana is yellow
cucomber is green
Plurals
[Edit] : As asked in the comment follows an example with pseudo-code of plural handling for english and french language. Its a very simple and not tested example but it gives you a hint.
description_banana = "{{#plurable}}a {{name}} is{{/plurable}} green" (Adjectives not getting "s" in plurals)
description_banana = "{{#plurable}}Une {{name}} est verte{{/plurable}}" (Adjectives getting an "s" in plural, so englobing the adjective as well)
info.plurable = function()
{
//Check if needs plural
//Parse each word with a space separation
//Add an s at the end of each word except ones from a map of common exceptions such as "a"=>"/*nothing*/", "is"=>"are" and for french "est"=>"sont", "une" => "des"
//This map/function is specific to each language and should be expanded at need.
}
This is quite simple and pretty straightforward.
First, you will need to add code to determine the Query String lang. For this, I use snippet taken from answer here.
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)')
.exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
And then, I use jQuery to handle ajax and onReady state processing:
$(document).ready(function(){
var possibleLang = ['en', 'id'];
var currentLang = getParameterByName("lang");
console.log("parameter lang: " + currentLang);
console.log("possible lang: " + (jQuery.inArray(currentLang, possibleLang)));
if(jQuery.inArray(currentLang, possibleLang) > -1){
console.log("fetching AJAX");
var request = jQuery.ajax({
processData: false,
cache: false,
url: "data_" + currentLang + ".json"
});
console.log("done AJAX");
request.done(function(data){
console.log("got data: " + data);
var output = Mustache.render("<h1>{{title}}</h1><div id='content'>{{content}}</div>", data);
console.log("output: " + output);
$("#output").append(output);
});
request.fail(function(xhr, textStatus){
console.log("error: " + textStatus);
});
}
});
For this answer, I try to use simple JSON data:
{"title": "this is title", "content": "this is english content"}
Get this GIST for complete HTML answer.
Make sure to remember that other languages are significantly different from EN.
In FR and ES, adjectives come after the noun. "green beans" becomes "haricots verts" (beans green) in FR, so if you're plugging in variables, your translated templates must have the variables in reverse order. So for instance, printf won't work cuz the arguments can't change order. This is why you use named variables as in Option 1 above, and translated templates in whole sentences and paragraphs, rather than concatenating phrases.
Your data needs to also be translated, so the word 'poop', which came from data - somehow that has to be translated. Different languages do plurals differently, as does english, as in tooth/teeth, foot/feet, etc. EN also has glasses and pants that are always plural. Other languages similarly have exceptions and strange idoms. In the UK, IBM 'are' at the trade show whereas in in the US, IBM 'is' at the trade show. Russian has several different rules for plurals depending on if they are people, animals, long narrow objects, etc. In other countries, thousands separators are spaces, dots, or apostrophes, and in some cases don't work by 3 digits: 4 in Japan, inconsistently in India.
Be content with mediocre language support; it's just too much work.
And don't confuse changing language with changing country - Switzerland, Belgium and Canada also have FR speakers, not to mention Tahiti, Haiti and Chad. Austria speaks DE, Aruba speaks NL, and Macao speaks PT.

Resources