Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does it even work with JSON object messages? #69

Open
OzanKurt opened this issue Aug 15, 2018 · 5 comments
Open

Does it even work with JSON object messages? #69

OzanKurt opened this issue Aug 15, 2018 · 5 comments

Comments

@OzanKurt
Copy link

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.

@OzanKurt
Copy link
Author

I'm not a Javascript developer, your package seems to be the only "working" one, so please keep it up to date.

@sentiasa
Copy link

sentiasa commented Dec 6, 2018

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({ })

@OzanKurt
Copy link
Author

OzanKurt commented Dec 6, 2018

Great job as well, thanks mate!

@alblandino
Copy link
Contributor

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.

@alwintom
Copy link

alwintom commented May 4, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants