philipp15b / php-i18n Goto Github PK
View Code? Open in Web Editor NEWSimple i18n class for PHP with caching and and ini, json and yaml support
License: MIT License
Simple i18n class for PHP with caching and and ini, json and yaml support
License: MIT License
How do I add variables to the value and how do I use them?
for example:
greeting = "Hello $name"
are you interested in getting additional globale namespaces into your class?
so that you can create the same constant for different pages or contexts for example.
usage would be like C::gettingstarted for the Content page or I::gettingstarted for an introduction page.
let me know if you would merge that. if so i would add backward compatibility, comments and documentation.
you can check the (very!!!!) basic implementation on my fork.
The underlying code uses vprintf
and outputs the resulting translation directly, instead of returning it.
The following example in the documentation will output the string, followed by its length, which is obviously wrong :
echo L::last_modified("today");
To fix this, use vsprintf, which behaves the same as vprintf but returns the string instead of outputting it directly.
mergeFallback option doesn't seem to work for sections or subkeys.
The subkeys from fallback language are not copied to the current language.
I've been trying the class for a while and seems to work pretty well, so thanks for coding this 😄
The only issue I've found is around vsprintf.
I had to change line 161
in order for it to work, where it says:
$compiled .= 'vsprintf(constant("self::" . $string), $args);' . "\n";
to:
$compiled .= 'return vsprintf(constant("self::" . $string), $args);' . "\n";
Let me know if that makes sense or if I'm missing something.
Cheers!
Inside https://github.com/Philipp15b/php-i18n#4-set-some-settings-if-necessary
original (not working):
setCachePath('./tmp/cache'); $i18n->setFilePath('./langfiles'); // language file path (the ini files) $i18n->setFallbackLang('en'); $i18n->setPrefix('I'); $i18n->setForcedLang('en') // force english, even if another user language is available $i18n->setSectionSeperator('_'); ?>improved (working):
setCachePath('./tmp/cache'); $i18n->setFilePath('./langfiles/lang/lang_{LANGUAGE}.ini'); // language file path (the ini files) $i18n->setFallbackLang('en'); $i18n->setPrefix('I'); $i18n->setForcedLang('en') // force english, even if another user language is available $i18n->setSectionSeperator('_'); ?>The error is in line 337, where the return statement does not have an trailing semicolon.
// Something of a sane version of PHP's array_merge
private static function array_extend($a, $b) {
foreach ($b as $key => $value) {
if (!array_key_exists($key, $a)) {
$a[$key] = $value;
}
}
return $a
}
It doesn't have to check for a string in fallbackLang if there is not translation for string?
E.g.
fallbackLang is "English" but current site language is "Russian". And there is not "greetings" in Russian. Wouldn't it return translation in English instead of returning "Fatal error: Undefined class constant 'greetings'"?
English language JSON:
{
"greetings": "Hello world!",
"logout": "Log out"
}
Russian language JSON:
{
"logout": "выйти"
}
I have noticed that translating characters which contains "&" sign should be properly scaped
Example:
\"%word1%,word2%\"
to output
"%word1%,word2%
But maybe this information will be useful in the docs
I have an ini file that looks like this:
[general]
...
yes = "Yes"
no = "No"
When I reload my page, there is this error:
Warning: syntax error, unexpected BOOL_TRUE in .../i18n/lang/lang_en.ini on line 11 in .../i18n/I18n.php on line 304
Warning: Invalid argument supplied for foreach() in ..../i18n/I18n.php on line 324
This /lang/lang_en.ini on line 11 points to the line yes = "Yes"
Not sure why it is considering "yes" as a boolean value and why that is invalid here.
The documentation says :
$i18n->setForcedLang('en'); // force english, even if another user language is available
But in i18n.class.php
the variable $forcedLang
is never used.
Maybe in the init() function you should test if this variable is not null ? And use it if the user set it ?
Something like
// search for language file
$this->appliedLang = NULL;
if ($this->forcedLang == NULL) {
foreach ($this->userLangs as $priority => $langcode) {
$this->langFilePath = $this->getConfigFilename($langcode);
if (file_exists($this->langFilePath)) {
$this->appliedLang = $langcode;
break;
}
}
} else {
$this->langFilePath = $this->getConfigFilename($this->forcedLang);
if (file_exists($this->langFilePath)) {
$this->appliedLang = $this->forcedLang;
}
}
Thanks a lot for providing i18n! As a php newby I had to figure out some things first with this package. My auto-detection works smooth and I am very happy already with this.
Now I am wondering:
Is there an easy way to make use of an HTML link to overwrite language parameters permanently for a user?
I understand I can toggle "lang" via the URL GET parameter via adding
?lang=de
My idea is to pass over the $_GET parameter to the $_SESSION variable. Yet even when I replicate the priority logic of public function getUserLangs() and added the code below to my "header"-include. The language somehow does still not remain the one I have passed over, despite the echo correctly showing me echo $_SESSION['lang']
is now "de", and is of type string, while echo $_GET['lang']
and forcedLanguage are not set.
I would have expected:
to be set.
In the docs, it is stipulated that the $_SESSION["lang"] variable will be taken into account to choose the language, but I did not find it in the file. I had to add the following lines in "public function getUserLangs()"
// 2nd highest priority: GET parameter 'lang'
if (isset($_GET['lang']) && is_string($_GET['lang'])) {
$userLangs[] = $_GET['lang'];
}
// xxx fix ---
if (isset($_SESSION['lang']) && is_string($_SESSION['lang'])) {
$userLangs[] = $_SESSION['lang'];
}
// --- fix xxx
// Lowest priority: fallback
$userLangs[] = $this->fallbackLang;
Did I overlooked something or is it the correct way to do it ?
I'm sure is it a UTF 8 problem, but i got ��� when change language
Is there a solution, how I can switch language during script execution?
I have the case where I send Emails/Notifications to the users by a cron script, depending on the defined user Language every User should got the Email/Notification in the correct language.
there is no support for dynamic calls to the derived class, I suggest to add the method "get".
I changed the class by modifying this
$compiled = "<?php class " . $this->prefix . " {\n";
$compiled .= $this->compile($config);
$compiled .= 'public static function __callStatic($string, $args) {' . "\n";
$compiled .= ' return vsprintf(constant("self::" . $string), $args);' . "\n";
$compiled .= "}\n";
into this:
$compiled = "<?php class " . $this->prefix . " {\n";
$compiled .= $this->compile($config);
$compiled .= 'public static function __callStatic($string, $args) {' . "\n";
$compiled .= ' return vsprintf(constant("self::" . $string), $args);' . "\n";
$compiled .= "}\n";
$compiled .= 'public static function get($string) {' . "\n";
$compiled .= ' return constant("self::" . $string);' . "\n";
$compiled .= "}\n}";
so now I can call L::get("myconstant")
I have the spyc class already autoloaded.
Would you mind adding a verifier that the class is not existent before including the vendor file?
Can I set to other language after "$i18n->init();"?
I am creating API for my mobile APP:
I think that store the translations in the cache file using some king of array instead constants will allow to use "dashed" and "dots" in the names.
For example, this is not possible with the current implementation
echo I::login.submit
and provide some king of (for example)
echo I::get('login.submit')
It is just a thought to know your opinion
Hello
Its working:
echo L::CATNAME; // Home
but this is not working:
echo L($cat->catName);
// CATNAME
Error:
Warning: constant(): Couldn't find constant L::CATNAME in /home/username/public_html/cache/Lisan/php_i18n_37afd09999aa4bfa94b3dc938a775239_L_en.cache.php on line 39
Why am I getting this error?
Thank you
Spyc has a composer package: https://packagist.org/packages/mustangostang/spyc, so there is no need to include it in this repository.
Hi @Philipp15b
I have a quick question.
As you can see in the Below Snippet. I'm setting the Language filename through the variable $lang
which is returned from the Database when the user lands on Dashboard after successful login.
$i18n = new i18n('lang/lang_' . $lang . '.json', 'langcache/' . $lang . '', $lang);
// Parameters: language file path, cache dir, default language (all optional)
// init object: load language files, parse them if not cached, and so on.
$i18n->init();
Which is creating a separate folder for each language. But the Cache filename contains en_cache.php
.
How can I replace it with language code like fr
, ta
Hi,
I don't understand right how the lang detection works.
How can I set the $_SERVER['HTTP_ACCEPT_LANGUAGE']
option as default?
Normally I thought the lib will use it if no one of the other option except the fallback will be true but I get everytime the english text and not german like the output from $_SERVER['HTTP_ACCEPT_LANGUAGE']
is.
I have also no forced language set.
I hope you can help me?
Best regards
For example like this:
1- Add to lang_en.ini
stringswithvar = "Test1: %1$s"
stringswithvars = "Test_number: %1$s Test_string: %2$s"
2.- Add to lang_en.json
"stringswithvar": "Test1: %1$s"
"stringswithvars": "Test_number: %1$s Test_string:%2$s"
3.- Add to lang_en.yml
stringswithvar: 'Test1: %1$s'
stringswithvars: 'Test_number: %1$s Test_string:%2$s'
4. And add to example.php
String with var(string):
String with var(integer):
String with vars(string):
String with vars(integer):
String with vars(combined):
Let's say I'd like primary language to be Dutch, so when someone visits the site expect the script to load the "lang_nl.json" file but, instead, it loads "lang_en.json".
My code is as follows:
$i18n = new i18n('lang/lang_{LANGUAGE}.json, 'cache/', 'nl');
$i18n->setFallbackLang('nl');
$i18n->init();
but with this when the person first visits the site and without setting ?lang=nl
it loads the English one...
How can I set nl to be the default?
If I set $i18n->setForcedLang('nl');
it always uses nl and stops using all other languages.
Solved.
Fatal error: Uncaught Error: Call to undefined function i18n\spyc_load_file() in /home/pablo/GitHub/trauma-emr-proto/i18n/I18n.php:302
Stack trace:
#0 /home/pablo/GitHub/trauma-emr-proto/i18n/I18n.php(149): i18n\I18n->load('/home/pablo/Git...')
#1 /home/pablo/GitHub/trauma-emr-proto/index.php(139): i18n\I18n->init()
#2 {main} thrown in /home/pablo/GitHub/trauma-emr-proto/i18n/I18n.php on line 302
estimate= 'Estimate'
[estimate]
createdon= 'Created on'
if I set a category and a string with same name, the page will return the error "Undefined Class Constant estimate"
error.
Hello, I'd like to use this library for translating my website. But I have all langage ressource in json format. I tryied to adapt a new format in your code but I'm not fluent in php so I didn't succeed. Do you planify a json plugin as yml?
Hi. I think there is an error in this function i18n.class.php
/**
* @deprecated Use setSectionSeparator.
*/
public function setSectionSeperator($sectionSeparator) {
$this->setSectionSeparator($setSectionSeparator);
}
I think it should be:
/**
* @deprecated Use setSectionSeparator.
*/
public function setSectionSeperator($sectionSeparator) {
$this->setSectionSeparator($sectionSeparator);
}
The option "mergeFallback" does not seem to do anything nor seems to be implement in the library.
Hi, sorry my english is not so good.
This php-i18n is very good.
But I have a question: Is the cache file never deleted?
Thank you for your help.
Hi,
I have a strange problem where I can't find a solution resp. a reason for it.
I got a fatal error when I use php-i18n in my index.php:
Fatal error: Uncaught Error: Undefined class constant 'login_failed' in /var/www/…/index.php:71 Stack trace: #0
My call of the php-i18n extension:
require_once 'vendor/philipp15b/php-i18n/i18n.class.php';
$i18n = new i18n();
$i18n->setCachePath('langcache');
$i18n->setFilePath('lang/lang_{LANGUAGE}.json');
$i18n->setPrefix('lang');
$i18n->init();
…
return msg($typeOfMsg, lang::login_failed);
…
msg
is my own errormessage function where the second paramter is the error message.
My german languagefile in lang/lang_de.json
:
{
"login": {
"failed": "Die Anmeldung schlug fehl! <br> Bitte füllen Sie alle Felder aus!",
"wrongpw": "Das Password ist falsch!",
"nopwfile": "Password Datei konnte nicht geöfnet werden!"
}
"browser": {
"somethingother": "Etwas anderes..."
}
}
I hope someone can give me a tip whats wrong?
Cheers
Please make new release, to update composer package, not using "minimum-stability": "dev".
There is a lot of good stuff since last release.
To accept language codes (like en_US or en-US)
delete this:
foreach ($userLangs as $key => $value) {
$userLangs[$key] = preg_replace('/[^a-zA-Z0-9]/', '', $value); // only allow a-z, A-Z and 0-9
}
and insert it:
foreach ($userLangs as $key => $value) {
$userLangs[$key] = preg_replace('/[^a-zA-Z_-]/', '', $value); // only allow a-z, A-Z and symbols like (_ and -)
}
Is there any way to get a list of messages used programmatically?
Alternatively, is there any way to synamically build message names? ${var}
syntax doesn't work here, but maybe there are other ways?
In the doc, there is this example:
echo L::last_modified("today");
That seems to output a text with the "today" replaced using some kind of variable name, but in the sample lang files, an example for that is missing.
What's the format of the lang files to support parameters?
In the readme and in the source you use the word "seperator" instead of the form "separator", you also have the method setSectionSeperator. I'm not good at english, but I think it's misspelled.
When a term doesn't exists I'm getting an exception "Fatal error: Uncaught Error: Undefined class constant".
It happens when two lang files exist but one has missing translations.
I have used the latest version of the source code to test out the fall back feature. However, it looks like the set language is being loaded in twice instead of the set language and the fall back language. This looks like a typo as instead of loading the passed in filename you load the set language.
When the above issue was sorted I ran into another small issue. While the array_merge function merges the files neatly I needed to return the merged array in order for the combined language file to be made available.
I'm new to GitHub but am willing to pull the code with the changes I made for you to look over and merge with your if your happy with the changes but would need a little direction.
Merging fall back code:
if ($this->mergeFallback) $config = self::array_extend($config, $this->load($this->getConfigFilename($this->fallbackLang)));
load function:
protected function load($filename) { $ext = substr(strrchr($filename, '.'), 1); switch ($ext) { case 'properties': case 'ini': $config = parse_ini_file($filename, true); break;
array_merge return $a.
Hey there,
I tried to load a .yaml file but it seems only .yml is possible.
PHP Fatal error: Uncaught RuntimeException: No language file was found.
.yaml is valid according to this: http://www.yaml.org/faq.html
(I will look into fixing this once I got some time)
Composer support would be nice. Are there any plans to do so?
I got different results with two different browser. At the back is opera, in the front is firefox. So by default both browser show different results.
I added the following line to the example.php to see whats in the userlangs array.
print_r($i18n->getUserLangs());
OS: Ubuntu 16.04
Opera Version: 46.0
Firefox Version: 54.0
We're starting integration into our app, and are getting a namespace conflict. Our application has a legacy I18n
class. Is there any way that we can use namespaces & PSR-4? I'm happy to create a MR.
Hi. I'm wondering if it will be a good idea to display the key instead of a null value if the key does not exists
// Just an example of possible implementation
// Note: This is PHP 7, but only to get the idea
return vsprintf(constant("self::" . $string), $args) ?? $string;
Why are there cache ?? are they really needed?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.