actimeo / ng2-i18next

use i18next with Angular2
MIT License
11 stars 9 forks source link

I18nDirective does not work with i18next-resource-store-loader #1

Closed mazswojejzony closed 8 years ago

mazswojejzony commented 8 years ago

When i18next-resource-store-loader is used there is no async request made to fetch translation resources and as a result this.i18n.alerts$.subscribe() works in a sync fashion what causes the obs variable to be undefined @ https://github.com/actimeo/ng2-i18next/blob/master/src/i18n-directive.ts#L48

The fix may be as simple as changing the line 48 to setTimeout(() => { obs.unsubscribe() }, 0);

feloy commented 8 years ago

Thanks for this report. Could you show me a simple case of code using i18next-resource-store-loader with ng2-i18next?

mazswojejzony commented 8 years ago

You just need to follow the i18next-resource-store-loader example which comes down to setting up a simple folder structure and the following snippet:

var resBundle = require(
  "i18next-resource-store-loader!../assets/i18n/index.js"
);

i18n.init({
  resources: resBundle
});

Then you just need to use i18nDirective, e.g. <span i18n="translation_key"></span>. In the console window you will see an error effectively saying the obs variable is undefined.

BTW: the ../assets/i18n/index.js can be an empty file - see here for a sample file: https://github.com/atroo/i18next-resource-store-loader/blob/master/test/data/i18n/index.js

feloy commented 8 years ago

I'm not sure this is a correct usage. i18n.init() is executed from the I18nService. So the "resources: resBundle" key/value should be added there. Is this really what you are doing, or do you run i18next.init() from elsewhere?

mazswojejzony commented 8 years ago

This is how my i18n init looks like. Looks like it works fine with the fix/work-around I mentioned in the original issue description.

import {I18nService} from 'ng2-i18next/ng2-i18next';

let resBundle = require('i18next-resource-store-loader!../../../locales/index.js');

export class InternationalizationService {
    constructor(public i18n: I18nService) {
        i18n.i18n.init({
            resources: resBundle,
            fallbackLng: 'en'
        });
    }
}
feloy commented 8 years ago

I understand it could work, but this is not the proper way to use the ng2-i18next library.

The problem is that the I18nService uses a hard-wired i18next.init(), with 2 objects to use (i18nextBrowserLanguageDetector and i18nextXHRBackend) and a fixed map passed as argument to i18next.init().

Instead, it would be interesting that the I18nService could be injected with some arguments (the list of objects to use and the map to pass as argument to the i18next.init() function). So you should not have to call i18next.init() again in your own Service.

I'll work on this implementation ASAP.

mazswojejzony commented 8 years ago

That would be great, thanks in advance!

feloy commented 8 years ago

I just updated the module ng2-i18next to 0.0.6 with this feature. Could you have a try?

I've also updated the demo app: https://github.com/actimeo/ng2-i18next-demo

mazswojejzony commented 8 years ago

Unfortunately it does not resolve the original issue. I use the following config:

export const I18N_PROVIDERS = [
    provide(I18nServiceConfig, {
        useValue: {
            use: [i18nextBrowserLanguageDetector],
            config: {
                detection: {order: ['navigator']},
                fallbackLng: 'en',
                resources: resBundle
            }
        }
    }),
    I18nService
];

I18N_PROVIDERS are used in the bootstrap(App, [...I18N_PROVIDERS]).

Without any modifications to the i18nDirective I still get the following error: Error: Uncaught (in promise): TypeError: Cannot read property 'unsubscribe' of undefined

feloy commented 8 years ago

Hi, I just put a new patch including the async'ed unsubscribe.

I'm not experimented with webpack, which is needed (am I right?) to 'require' the index.js like this: let resBundle = require('i18next-resource-store-loader!../../../locales/index.js');

Is there another way to include this file without webpack? (i'm using angular-cli)

mazswojejzony commented 8 years ago

Thanks, now it works fine!

Yes, webpack is needed to use the i18next-resource-store-loader. If you want to test the resources option you may simple hard-code a structure like this:

{
    "en": {
        "translation": {
            "map": "Map"
        }
    }
}