Does it even work with JSON object messages?
Opened this issue ยท 5 comments
I tried:
{
"en": {"Yes": "Yes", "No": "No"}},
"de": {"Yes": "Ja", "No": "Nein"}}
}
window.Lang.setMessages({
'en': en,
'de': de,
});
It parses keys to be flattened like this: de.No
and then, of course, it cannot find the key.
Then I flattened my messages object to be so:
{
"en.Yes": "Yes",
"en.No": "No",
"de.Yes": "Ja",
"de.No": "Nein",
}
window.Lang.setMessages({
'en': en,
'de': de,
});
and it worked.
What is the point of this approach? Why would I need to loop through all my language keys and flatten them?
Since Laravel provided us JSON translations, you should make a configuration option for that.
Lang.prototype._getMessage = function(key, locale) {
locale = locale || this.getLocale();
if (this.messages[locale] === undefined) {
locale = this.getFallback();
}
if (this.messages[locale][key] === undefined) {
locale = this.getFallback();
}
if (this.messages[locale][key] === undefined) {
return null;
}
return this.messages[locale][key];
}
I believe the code above is pretty self-explanatory.
I'm not a Javascript developer, your package seems to be the only "working" one, so please keep it up to date.
This snippet is a life saver, finally got it working with es.json
.
Let me share the Laravel-end for future-comers. P.S: I am not sure if this is the most efficient way but works so far :)
class ComposerServiceProvider extends ServiceProvider
{
public function boot()
{
$languages = $this->getLanguages();
View::composer('*', function($view) use ($languages) {
$view->with('languages', $languages);
});
}
}
protected function getLanguages() {
$es = json_decode(file_get_contents(resource_path('lang') . "/es.json"));
$esArray = (array) $es;
$englishKeys = array_keys($esArray);
$englishArray = array_combine($englishKeys, $englishKeys);
return [
'en' => $englishArray,
'es' => $esArray
];
}
}
// master.blade.php
<script>
window.default_locale = "{{ config('app.locale') }}";
window.fallback_locale = "{{ config('app.fallback_locale') }}";
window.languages = @json($languages);
</script>
// app.js
import Lang from 'lang.js';
Vue.prototype.trans = new Lang( { messages: window.languages, locale: window.default_locale, fallback: window.fallback_locale } );
// And Above Chunk ๐
Lang.prototype._getMessage = function(key, locale) {
locale = locale || this.getLocale();
if (this.messages[locale] === undefined) {
locale = this.getFallback();
}
if (this.messages[locale][key] === undefined) {
locale = this.getFallback();
}
if (this.messages[locale][key] === undefined) {
return null;
}
// Added this one - if key value doesn't found, return to fallback
// To handle this case: {"Hello: ""}
if (!this.messages[locale][key]) {
locale = this.getFallback();
}
return this.messages[locale][key];
}
new Vue({ })
Great job as well, thanks mate!
Hello @OzanKurt, it is possible that it has been difficult for you to navigate different levels of an object and that's why he did it type Chain "language.property" (it's just a speculation) but seeing this I think it would be good a PR in this part and Talk to see if it is feasible.
I was also looking for a way to use translation strings as key (https://laravel.com/docs/7.x/localization#using-translation-strings-as-keys). As the OP has explained, the _parseKey seems to not care about this scenario.
So if I have the following language key
es: {'Hello': 'Hola'}
The expected result when I run the following is
Lang.get('Hello') is 'Hola'
But the _parseKey method instead attempts to find the key 'es.Hello' which of course does not exist.
Since laravel's JSON translation files are only 1 level deep, my solution was to alter _getMessage() like the following
* Returns a translation message. Use `Lang.get()` method instead, this methods assumes the key exists.
*
* @param key {string} The key of the message.
* @param locale {string} The locale of the message
*
* @return {string} The translation message for the given key.
*/
Lang.prototype._getMessage = function(key, locale) {
locale = locale || this.getLocale();
let originalLocale = locale;
// Handle the scenario where the tranlation string is used as the key.
// (https://laravel.com/docs/6.x/localization#using-translation-strings-as-keys)
// In this case the Key should be present at the root of the locale.
if (typeof(this.messages[locale]) === 'undefined') {
// The given locale does not have keys at the root, use the fallback instead.
locale = this.getFallback();
}
// See if the key is defined.
if (typeof(this.messages[locale]) !== 'undefined') {
if (typeof(this.messages[locale][key]) !== 'undefined') {
return this.messages[locale][key];
}
}
//Try with the fallback as well. if we haven't looked there already.
if (locale === originalLocale) {
locale = this.getFallback();
if (typeof(this.messages[locale]) !== 'undefined') {
if (typeof(this.messages[locale][key]) !== 'undefined') {
return this.messages[locale][key];
}
}
}
// If we reach here, that means the traslation key did not exist in the provided locale
// nor the fallback locale. At this point proceed as normal and expect the rest of the code
// to find a valid translation or return the key itself as the translation
// (which also takes care of 'Translation strings as key')
// Reset to the original locale.
locale = originalLocale;
key = this._parseKey(key, locale);
// Ensure message source exists.
if (this.messages[key.source] === undefined && this.messages[key.sourceFallback] === undefined) {
return null;
}
// Get message from default locale.
var message = this.messages[key.source];
var entries = key.entries.slice();
var subKey = entries.join('.');
message = message !== undefined ? this._getValueInKey(message, subKey) : undefined;
// Get message from fallback locale.
if (typeof message !== 'string' && this.messages[key.sourceFallback]) {
message = this.messages[key.sourceFallback];
entries = key.entries.slice();
subKey = '';
while (entries.length && message !== undefined) {
var subKey = !subKey ? entries.shift() : subKey.concat('.', entries.shift());
if (message[subKey]) {
message = message[subKey]
subKey = '';
}
}
}
if (typeof message !== 'string') {
return null;
}
return message;
};
This code has worked for me when I load the JSON translation to the root like so:
import Lang from 'lang.js';
'fr': require('../../../lang/fr.json'),
'fr.misc': require('../../../lang/fr/misc.php'),
'fr.messages': require('../../../lang/fr/messages.php'),
'fr.pagination': require('../../../lang/fr/pagination.php'),
// Fallbacks
'en.misc': require('../../../lang/en/misc.php'),
'en.messages': require('../../../lang/en/messages.php'),
'en.pagination': require('../../../lang/en/pagination.php'),
window.lang = new Lang({
locale: 'fr',
messages: messages,
fallback: 'en',
});
I am providing an English version of the JSON file as the key itself is the valid English translation.
Added a PR here #83