Coder Social home page Coder Social logo

vazco / meteor-universe-i18n Goto Github PK

View Code? Open in Web Editor NEW
122.0 122.0 30.0 431 KB

Internationalization package for Meteor with React integration.

Home Page: https://atmospherejs.com/universe/i18n

License: MIT License

JavaScript 13.41% Shell 1.06% TypeScript 81.94% HTML 0.53% Svelte 3.06%
hacktoberfest i18n internationalization translation

meteor-universe-i18n's Introduction

vazco/universe:i18n

GitHub Workflow Status GitHub


Internationalization package that offers much better performance than others.

The package supports:

  • namespacing of translation strings
  • YAML file formats
  • string interpolation
  • both types of parameters (named and positional)
  • typographic notation of numbers
  • regional dialects inheritance mechanism (e.g. 'en-US' inherits from translations assigned to 'en')
  • ECMAScript 6 modules
  • supports dynamic imports (Client does not need to download all translations at once)
  • remote loading of translations from a different host

Table of Contents

Installation

$ meteor add universe:i18n

Typescript

This package is integrated with zodern:types package. If you use zodern:types package in your project, it will automatically download the current type definitions.

However, you can still use types from the DefinitelyTyped package.

$ meteor npm install --save @types/meteor-universe-i18n

Migration to v2

  • Locales and currency data have been removed. That means, the following functions are no longer available: parseNumber, getLanguages, getCurrencyCodes, getCurrencySymbol, getLanguageName, getLanguageNativeName and isRTL. If your app needs them, check if the Intl API suits your needs. If not, copy the values you need from v1 source
  • The _purify option has been removed, as it wasn't working on the server anyway. For detailed explanation and an alternative, see this comment
  • Both createTranslator and createReactiveTranslator have been removed. If your project is using them, simply create your own helpers on top of getTranslation. You can copy or modify implementation from the v1 source.
  • The built-in React integration is no longer there, i.e., both createComponent and getRefreshMixin functions have been removed. Refer to the Integration with React section for details.
  • The Blaze integration package (universe-i18n-blaze) is deprecated. Refer to the Integration with Blaze section for details.

If you want to read more about v2, check out the roadmap as well as the main pull request.

Usage

import i18n from 'meteor/universe:i18n';

Setting/getting locale

i18n.setLocale('en-US', params);
i18n.getLocale(); // en-US

Params in setLocale are optional yet offer additional possibilities:

  • noDownload - disables downloading translation file on the client (client side)
  • silent - protects against broadcasting the refresh event (both sides)
  • async - downloads translation file in an async way (client side)
  • fresh - downloads fresh translations (ignores the browser cache)

If you want to use the browser's locale, you can do it as follows:

// somewhere in the page layout (or possibly in the router?)
function getLang() {
  return (
    navigator.languages?.[0] ||
    navigator.language ||
    navigator.browserLanguage ||
    navigator.userLanguage ||
    'en-US'
  );
}

i18n.setLocale(getLang());

Keep in mind though that it will work on the client side and in server methods called from client (on the same connection). In other places where connection is not detected, you must provide it self. By the way, It's good option is also use 'accept-language' header to recognize client's locale on server side.

Adding translations by methods

import i18n from 'meteor/universe:i18n';

i18n.addTranslation('en-US', 'Common', 'no', 'No');
i18n.addTranslation('en-US', 'Common.ok', 'Ok');

i18n.addTranslations('en-US', {
  Common: {
    hello: 'Hello {$name} {$0}!',
  },
});

i18n.addTranslations('en-US', 'Common', {
  hello: 'Hello {$name} {$0}!',
});

Getting translations

You can obtain translation strings by using i18n.getTranslation() or, quicker, calling i18n.__()

i18n.__(key);
i18n.__(key, params);
i18n.__(namespace, key, params);
i18n.__(key, key, key, key, params);

// same with "getTranslation", e.g.:
i18n.getTranslation(key, key, key, key, params);

String Interpolation

If needed, parameters can be passed as the last one of the function arguments, as an array or an object since they can be named or positional (ie. indexed). Additionally, for positional parameters it is irrelevant whether they are passed as an array or an object with keys '0', '1', '2'... Besides, 'positional' properties of such an object can be mixed with named ones.

_namespace: ''
hello: Hello {$name}!
lengthOfArr: length {$length}
items: The first item is {$0} and the last one is {$2}!
i18n.__('hello', { name: 'Ania' }); // output: Hello Ania!
i18n.__('lengthOfArr', { length: ['a', 'b', 'c'].length }); // output: length 3
i18n.__('items', ['a', 'b', 'c']); // output: The first item is a and the last one is c!

Dynamic imports

Loading all your locale files on the client side may unnecessarily increase the bundle size of the client application. Instead, you can use dynamic import to load additional locales only when necessary. There are two ways of doing so:

Method 1:

Using import() with dynamic expressions as explained in the meteor documentation, e.g.

const onChangeLocale = locale => {
  if (false) {
    import('../translations/en.i18n.yml');
    import('../translations/es.i18n.json');
    import('../translations/fr.i18n.yml');
    import('../translations/pl.i18n.yml');
    // import all locales...
  }
  import(`../translations/${locale}.i18n.json}`).then(() => {
    i18n.setLocale(locale);
  });
};

Method 2:

  1. Load locales on the server side. Either import files statically or use addTranslations if loading locales from other sources, e.g. database.

  2. On the client call setLocale which will load the respective locale via a GET request to the configured hostUrl.

Translations files

Instead of setting translations directly through i18n.addTranslation(s), you can store them in YAML or JSON files, named .i18n.yml, .i18n.json accordingly. Translation files should be imported on the client side:

// client/main.jsx
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import { App } from '/imports/ui/App';

import '../i18n/en.i18n.json';
import '../i18n/de.i18n.json';

Meteor.startup(() => {
  render(<App />, document.getElementById('react-target'));
});

Recognition locale of translation

Files can be named freely as long as they have their respective locale declared under the key '_locale'.

# translation.i18n.yml
_locale: en-US
title: Title

Otherwise, files should be named after their respective locales or placed in directories named accordingly.

en.i18n.yml
en.i18n.json
en_us.i18n.yml
en-us.i18n.yml
en/us.i18n.yml
en-US/someName.i18n.yml
someDir/en-us/someName.i18n.yml

Namespace

Translations in a translation file can be namespaced (depending on where they are located). A namespace can be set up only for a whole file, yet a file as such can add more deeply embedded structures.

Tip: A good practise is using PascalCase for naming of namespaces and for leafs use camelCase. This helps protect against conflicts namespace with string.

Splitting keys in file

Comma-separated or x-separated keys in file e.g.:

_splitKey: '.'
Chapter.title: Title
Chapter.xxx: XXX

or

_splitKey: ':'
Chapter:title: Title
Chapter:xxx: XXX

Will be loaded as following structure:

Chapter:
  title: Title
  xxx: XXX

Translation in packages

For example, translations files in packages are by default namespaced by their package name.

// file en.i18n.json in the universe:profile package
{
  "_locale": "en",
  "userName": "User name"
}
i18n.__('universe:profile', 'userName'); // output: User name

You can change a default namespace for a file by setting a prefix to this file under the key "_namespace".

// file en.i18n.json in the universe:profile package
{
  "_locale": "en-US",
  "_namespace": "Common",
  "userName": "User name"
}

And then:

i18n.__('Common', 'userName'); // output: User name
i18n.__('Common.userName'); // output: User name

TIP: You can also add translations from a package on the top-level by passing empty string "" in the key "_namespace".

Translation in application

Here your translations by default are not namespaced which means that your translations from an application space are top-level and can override every other namespace.

For example:

# file en_us.i18n.yml in an application space (not from a package)
_locale: en-US
userName: user name
i18n.__('userName'); // output: User name

If you want to add translations under a namespace, you should define it in the key '_namespace'.

_locale: en-US
_namespace: User.Listing.Item
userName: User name
i18n.__('User.Listing.Item.userName'); // output: User name
i18n.__('User', 'Listing', 'Item.userName'); // output: User name

Listener on language change

// adds a listener on language change
i18n.onChangeLocale(function (newLocale) {
  console.log(newLocale);
});

// removes a listener
i18n.offChangeLocale(fn);

// does something on the first language change and then stops the listener
i18n.onceChangeLocale(fn);

Pluralization

With this package, you can translate with pluralization. To do that you need to use the pipe separator | in your locale translations, like in the example below:

_locale: 'en'
phone: 'zero phones | one phone | two phones | {$_count} phones'

Then just add the _count argument to the getTranslation options:

i18n.getTranslation('phone', { _count: 0 }); // -> zero phones
i18n.getTranslation('phone', { _count: 1 }); // -> one phone
i18n.getTranslation('phone', { _count: 2 }); // -> two phones
i18n.getTranslation('phone', { _count: 3 }); // -> 3 phones
i18n.getTranslation('phone', { _count: 1000 }); // -> 1000 phones

It is possible to override the default separator | with custom one by adding the pluralizationDivider property to i18n.setOptions.

Custom rules

Some languages (e.g. from the Slavic group) may have more complicated pluralization rules. It is possible to define custom pluralization rules to handle such cases. To do that add the pluralizationRules property to i18n.setOptions:

i18n.setOptions({
  // Key - language to apply the rule for, e.g. 'pl'
  // Value - function that takes the count as argument and returns index of the correct pluralization form
  pluralizationRules: {
    pl: count => {
      const tens = count % 100;
      const units = tens % 10;

      if (tens > 10 && tens < 20) return 2;
      if (units === 0) return 2;
      if (tens === 1 && units === 1) return 0;
      if (units > 1 && units < 5) return 1;
      return 2;
    },
  },
});
_locale: 'pl'
phone: '{$_count} telefon | {$_count} telefony | {$_count} telefonów'

Template:

i18n.getTranslation('phone', { _count: 0 }); // -> 0 telefonów
i18n.getTranslation('phone', { _count: 1 }); // -> 1 telefon
i18n.getTranslation('phone', { _count: 2 }); // -> 2 telefony
i18n.getTranslation('phone', { _count: 3 }); // -> 3 telefony
i18n.getTranslation('phone', { _count: 4 }); // -> 4 telefony
i18n.getTranslation('phone', { _count: 5 }); // -> 5 telefonów
i18n.getTranslation('phone', { _count: 232 }); // -> 232 telefony
i18n.getTranslation('phone', { _count: 1000 }); // -> 1000 telefonów

API

// adds a translation
i18n.addTranslation(locale, namespace, key, ..., translation);

// adds translations (same as addTranslation)
i18n.addTranslations(locale, namespace, translationsMap);

// gets a translation in params (_locale)
i18n.getTranslation(namespace, key, ..., params);
i18n.__(namespace, key,..., params);

// get translations (locale is by default set to the current one)
i18n.getTranslations(namespace, locale);

// options
i18n.setOptions({
    // default locale
    defaultLocale: 'en-US',

    // opens string
    open: '{$',

    // closes string
    close: '}',

    // decides whether to show when there's no translation in the current and default language
    hideMissing: false,

    // url to the host with translations (default: Meteor.absoluteUrl())
    // useful when you want to load translations from a different host
    hostUrl: 'http://current.host.url/',

    // (on the server side only) gives you the possibility to add/change response headers
    translationsHeaders = {'Cache-Control':'max-age=2628000'},

    // synchronizes server connection with locale on client. (method invoked by client will be with client side locale)
    sameLocaleOnServerConnection: true
});

// supports dynamic imports
import('../fr.i18n.yml');

// changes locale
i18n.setLocale(locale, params);
// this function on the client side returns a promise (but only if parameter `noDownload !== true`)
// Called from client, it sets locale for connection on server side.
// It mean that method invoked by client will be with client side locale.
// You can turn off this synchronization by setting the global option `sameLocaleOnServerConnection: false`

// Setting locale for connection (if `connectionId` is not provided system will try detect current connection id)
i18n.setLocaleOnConnection(locale, connectionId=);
// this function sets locale in all places, where connection can be detected (like meteor methods)

// gets the current locale
i18n.getLocale();

// fetches translations file from the remote server (client/server)
i18n.loadLocale(locale, params)
// @params on the client { fresh = false, async = false, silent = false,
// host = i18n.options.hostUrl, pathOnHost = i18n.options.pathOnHost }
// @params on server { queryParams = {}, fresh = false, silent = false,
// host = i18n.options.hostUrl, pathOnHost = i18n.options.pathOnHost }
// on the server side, this method uses HTTP.get with query parameter `type=json` to fetch json data
// on the client side, it adds a new script with translations to the head node
// this function returns a promise

// executes function in the locale context,
i18n.runWithLocale(locale, func)
// it means that every default locale used inside a called function will be set to a passed locale
// keep in mind that locale must be loaded first (if it is not bundled)

Integrations

This section showcases some of the ways of integrating universe:i18n with different frameworks. More detailed examples can be found in the integrations directory.

Integration with React

There are few different ways to integrate this package with a React application. Here is the most "React-way" solution facilitating React Context:

// imports/i18n/i18n.tsx
import { i18n } from 'meteor/universe:i18n';
import React, {
  ReactNode,
  createContext,
  useCallback,
  useContext,
  useEffect,
  useState,
} from 'react';

const localeContext = createContext(i18n.getLocale());

export type LocaleProviderProps = { children: ReactNode };

export function LocaleProvider({ children }: LocaleProviderProps) {
  const [locale, setLocale] = useState(i18n.getLocale());
  useEffect(() => {
    i18n.onChangeLocale(setLocale);
    return () => {
      i18n.offChangeLocale(setLocale);
    };
  }, [setLocale]);

  return (
    <localeContext.Provider value={locale}>{children}</localeContext.Provider>
  );
}

export function useLocale() {
  return useContext(localeContext);
}

export function useTranslator(prefix = '') {
  const locale = useLocale();
  return useCallback(
    (key: string, ...args: unknown[]) =>
      i18n.getTranslation(prefix, key, ...args),
    [locale],
  );
}

Created above useTranslator hook can be used in the following way:

// imports/ui/App.tsx
import React from 'react';
import { LocaleProvider, useTranslator } from '/imports/i18n/i18n';

const Component = () => {
  const t = useTranslator();
  return (
    <div>
      <h1>{t('hello')}</h1>
    </div>
  );
};

export const App = () => (
  <LocaleProvider>
    <Component />
  </LocaleProvider>
);

Here are other options for React integration:

The most straight-forward approach. Gets transaltion every time language is changed.
import { i18n } from 'meteor/universe:i18n';
import { useEffect, useState } from 'react';

export function useTranslation(key: string, ...args: unknown[]) {
  const setLocale = useState(i18n.getLocale())[1];
  useEffect(() => {
    i18n.onChangeLocale(setLocale);
    return () => {
      i18n.offChangeLocale(setLocale);
    };
  }, [setLocale]);
  return i18n.getTranslation(key, ...args);
}
Improved version of the solution above. Gets translation every time acctual translation changes, instead of reacting on language changes. Usefull when different languages has same translations.
import { i18n } from 'meteor/universe:i18n';
import { useEffect, useState } from 'react';

export function useTranslation(key: string, ...args: unknown[]) {
  const getTranslation = () => i18n.getTranslation(key, ...args);
  const [translation, setTranslation] = useState(getTranslation());
  useEffect(() => {
    const update = () => setTranslation(getTranslation());
    i18n.onChangeLocale(update);
    return () => {
      i18n.offChangeLocale(update);
    };
  }, []);
  return translation;
}
The meteor-way solution that facilitates ReactiveVar and useTracker. The advantage of this approach is creating only one listener instead of creating a listener on every locale change.
import { i18n } from 'meteor/universe:i18n';
// https://docs.meteor.com/api/reactive-var.html
import { ReactiveVar } from 'meteor/reactive-var';
// https://blog.meteor.com/introducing-usetracker-react-hooks-for-meteor-cb00c16d6222
import { useTracker } from 'meteor/react-meteor-data';

const localeReactive = new ReactiveVar<string>(i18n.getLocale());
i18n.onChangeLocale(localeReactive.set);

export function getTranslationReactive(key: string, ...args: unknown[]) {
  localeReactive.get();
  return i18n.getTranslation(key, ...args);
}

export function useTranslation(key: string, ...args: unknown[]) {
  return useTracker(() => getTranslationReactive(key, ...args), []);
}

Integration with Blaze

import { i18n } from 'meteor/universe:i18n';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';

const localeReactive = new ReactiveVar<string>(i18n.getLocale());
i18n.onChangeLocale(localeReactive.set);

Template.registerHelper('__', function (key: string, ...args: unknown[]) {
  localeReactive.get();
  return i18n.getTranslation(key, ...args);
});

Integration with SimpleSchema package

Add following-like code to main.js:

const registerSchemaMessages = () => {
  SimpleSchema.messages({
    required: i18n.__('SimpleSchema.required'),
  });
};

i18n.onChangeLocale(registerSchemaMessages);
registerSchemaMessages();

Put the default error messages somewhere in your project on both sides e.g.:

_locale: en
_namespace: SimpleSchema

required: '[label] is required'
minString: '[label] must be at least [min] characters'
maxString: '[label] cannot exceed [max] characters'
minNumber: '[label] must be at least [min]'
maxNumber: '[label] cannot exceed [max]'
minNumberExclusive: '[label] must be greater than [min]'
maxNumberExclusive: '[label] must be less than [max]'
minDate: '[label] must be on or after [min]'
maxDate: '[label] cannot be after [max]'
badDate: '[label] is not a valid date'
minCount: 'You must specify at least [minCount] values'
maxCount: 'You cannot specify more than [maxCount] values'
noDecimal: '[label] must be an integer'
notAllowed: '[value] is not an allowed value'
expectedString: '[label] must be a string'
expectedNumber: '[label] must be a number'
expectedBoolean: '[label] must be a boolean'
expectedArray: '[label] must be an array'
expectedObject: '[label] must be an object'
expectedConstructor: '[label] must be a [type]'
RegEx:
  msg: '[label] failed regular expression validation'
  Email: '[label] must be a valid e-mail address'
  WeakEmail: '[label] must be a valid e-mail address'
  Domain: '[label] must be a valid domain'
  WeakDomain: '[label] must be a valid domain'
  IP: '[label] must be a valid IPv4 or IPv6 address'
  IPv4: '[label] must be a valid IPv4 address'
  IPv6: '[label] must be a valid IPv6 address'
  Url: '[label] must be a valid URL'
  Id: '[label] must be a valid alphanumeric ID'
keyNotInSchema: '[key] is not allowed by the schema'

Running Tests

meteor test-packages --driver-package meteortesting:mocha universe:i18n

License

Like every package maintained by Vazco, universe:i18n is MIT licensed.

meteor-universe-i18n's People

Contributors

bompi88 avatar cristo-rabani avatar damien-monni avatar fadomire avatar hazemkhaled avatar idmadj avatar janowsiany avatar jkawamoto avatar jsusmillan avatar macrusher avatar mathewmeconry avatar michalw avatar mstanuch avatar piotrpospiech avatar radekmie avatar sabativi avatar sakulstra avatar skyb4ss avatar storytellercz avatar user1901 avatar zendranm avatar ziarno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

meteor-universe-i18n's Issues

Meteor 1.3 beta 4 - no translations

Hi,

I'm in the process of upgrading my project to use Meteor 1.3 with the new modules support.

Everything works with the exception of this project, which can't find my translations. If as if the son files have been ignored.

Thanks.

i18n.json files

Hi!
I'm using meteor-universe-i18n for internationalization of a project.
I keep translations in json files. I have en.i18n.json, ru.i18n.json and fr.i18n.json.
But after loading there are only 'en' and 'ru' translations in i18n object.
How can I load 'fr' translations?
My OS is Windows 7. I tried to add French language but it didn't work.

Get Raw HTML from i18n ?

Hello,

i was wondering if it is possible to get raw html and not just text from this library ?

thanks

i18n.createTranslator doesn't work properly

i18n.createTranslator doesn't work properly.

if you call translate(locale) - defined below -, sometimes the expected output doesn't return.

import i18n from 'meteor/universe:i18n';

export function translate(locale,key){
    let translator = i18n.createTranslator('', locale)  
    return translator(key)   
}

english language file always loads

is there any way of not loading the english locale when the app starts? I have the UNIVERSE_I18N_LOCALES set to pl and in my /lib/config.jsx file _i18n.setLocale('pl');, but I can see the en.i18n.json file always being loaded in the browser's console (along with pl.i18n.json)

ReferenceError: Can't find variable: i18n

Can't find the i18n variable on the client. I just added the package to my project for testing as follow:

1 - meteor add universe:i18n
2 - open browser console and type i18n
3 - ReferenceError: Can't find variable: i18n

Missing exports??

Waiting for translations to be loaded

Hi,

How can I make my client code to wait until the translations for the user locale are loaded? I couldn't find it on the documentation and when I first access the app I can see the keys being displayed and only (shortly) after I see the translation being applied.

Thanks

[SOLVED] Issues when using https

Hi,

I have been using this package and it is really great, thank you for working on it!

I have only one issue: I have a server setup to serve my app in https, and when doing that it gives me an issue when trying to load additional language files since those seems to be served in http automatically. Is there a workaround for it?

Cheers,

Server-side i18n using Locale Defined by Client

I want to use this package for both client-side as well as server-side i18n. Client side internationalization and switching between locales works just fine.

However, i18n on server-side is causing some issues:

We were able to retrieve the accept-language from the HTTP headers by using the headers package.

Our application contains something along these lines:

if(Meteor.isServer) {
  var self=this;
  console.log('server headers: ');
  console.log(headers.get(self)['accept-language']); // yields en-us which defaults on my machine
}

The locale in the header is always en-us which is the default on my machine. Even if the client switches the language (via i18n.setLocale()) this value remains unchanged.

How would we implement the server-side i18n and “notify” the server once the client changes its locale? Error messages by the server and form labels (provided by vazco/uniforms) should be translated.

hello tagType='h1' no workink

Hello, the file translation work but spam is not changed by h1

this is my componet

import React from 'react';
const T = i18n.createComponent(i18n.createTranslator('home'));

class AppContainer extends React.Component {
constructor(props) {
super(props);
this.displayName = 'AppContainer';
}
render() {
return

   <T tagType='h1'>default_title</T>
   <T props={{ className: 'text-center'}}>default_description</T>

    </div>;
}

}

export default AppContainer;

Problem with <T> component

When I'm trying to show translated message throw React component I get an error in a console:

Warning: getInitialState was defined on T, a plain JavaScript class. This is only supported for classes created using React.createClass. Did you mean to define a state property instead?

Anyway translated message is shown, but why this error may appear?

I use Meteor 1.3, React, "ecmascript" package. Here is my code:

import React from 'react';

const T = i18n.createComponent();

export default class Header extends React.Component {
  render() {
    return (
      <div>
        <T>test</T>
      </div>
    );
  }
}

How to load translation file?

In the API section of the docs it mentions i18n.loadLocale(locale, params) so is this what is used to load in a file of translations?
If so, do you also have to add the line i18n.setLocale() above it?
Also, where do you run these line - in the top of the file before the component, or in componentDidMount ?

Here is what I am trying so far and I am getting this error in the browser console:

http://localhost:3000/universe/locale/en?ts=1477060272095 net::ERR_CONNECTION_REFUSED

Code so far:

import { Meteor } from 'meteor/meteor';
import React from 'react';
import i18n from 'meteor/universe:i18n';

export default class MyComponent extends React.Component {
    componentDidMount() {
        i18n.setLocale("en-GB");
    }

    render(){
        return (
            <div>{i18n.__('hello_world')}</div>
        )
    }
};

The translation file for /i18n/en-GB.i18n.json is:

{
  "hello_world" : "Hello World!"
}

Component <T> returns span

Hello!
Do you know why (sometimes) component T = i18n.createComponent() returns value inside <span> tag?
Although my en.i18n.json file is clear (text only)

Changes to yml files not reflected in client

It might have to do with meteor 1.3... When I change yml file, only the server gets restarted. The client doesn't reload. Even when reloading the page, the translations are still the old ones. I had to explicitly open and reload /universe/locale/de-DE and then reload the client, to get the updated translations.

Usage (Meteor 1.3)

Hi,

I have a feeling I have missed something terribly obvious.

Using Meteor 1.3 (8)

import {_i18n} from 'meteor/universe:i18n'; - OK

_i18n.__('a.b.c');

with yml file en-au.i18n.yml (the only one there, and locale is returning as en-AU in the browser) (or en-AU, or en).

yml file contents:

a:
  b:
    c: "Some string"

Is returning 'a.b.c' instead of the corresponding "Some string".

Have also tried just using unnested values and it still just returns the key.

However _i18n.addTranslations works fine. :/ What have I neglected to notice?

Plural support

Can you please add support for selecting the correct plural translation based on a count value?

React is not defined

Hi,

it seems like React isn't defined in your _i8n file on line 66:

TypeError: Cannot read property 'PropTypes' of undefined at Object.createComponent (packages/universe:i18n/lib/i18n.js:66:27)

Regards,

An example using files

Hello,
I'm trying to use files to store my translations, but however much I read the docs they remain hopelessly obscure to me. while "i18n.addTranslation" works, adding my translations to a YAML file does not for whatever reason. A live-example would be most welcome as searching for one turned up nothing.

Thank you.

Confused about translation files

Hei.
Im really confused how this should work with translation files.
Translation file is working with en-US.
I am setting i18n.setLocale('ru-RU') in imports/api/client/routes.js
I have folder lib/translations/ru-ru/pages.i18n.json
Then i even made folder to public/translations/ru/pages.i18n.json
pages is the _namespace.
Contents of the pages.i18n.json file.

{
  "_locale": "ru",
  "_namespace": "pages",
  "default_title": "bla bla",
  "default_description": "bal bla"
}

Im setting custom urls and path etc.

i18n.setOptions({
  hostUrl: 'http://test.example.com:3000/',
  pathOnHost: 'translations/'
});

I see in my source that i have scripts tag in head with url http://test.example.com:3000/translations/ru
but this should not be right.

Am i missing something?

Multiple variables in translation stings

ask: Amount ({$min} - {$max}). Empty = {$max}
// Now
i18n.getTranslation('ask', {min: 10, max: 20}); // 'Amount (10 - 20). Empty = {$max}'
// Expected
i18n.getTranslation('ask', {min: 10, max: 20}); // 'Amount (10 - 20). Empty = 20'

hasTranslation

Hello, what is the best way to check whether a translation exists?
At the moment I'm using
__(x) !== x
which is not so nice ;)

Client side loadLocale call is not triggering server side loadLocale

Hi,
Maybe I misunderstood "remote loading of translations from different host" feature.
I would like to store translation files on remote http file server. Now when client part is calling meteor server for translation server part is just checking cache for it but is not querying http file server. Is it intended behaviour ?

JSON\YML being served by the wrong server

The application I'm currently working on is a widget so there's always the need for the two servers. One, running on port 1337 and the server for the widget which is running on port 3000.
Despite the fact that the translation files exist on the widget server, everytime Universe tries to load the file, it tries on the following URL: localhost:1337. Considering that the URL returns an HTML page, the application ends up crashing producing the error: "Uncaught SyntaxError: Unexpected token <".
The whole problem here is that universe should be making the request based on the port where it's running and not on the one that loads the widget.

Getting error in the translation file without declared "_locale"

Hello,
while testing this module I've getting error like this:

Your app is crashing. Here's the latest log.

Errors prevented startup:

While building the application:
:43:21: Cannot call method 'toLowerCase' of undefined (compiling both/i18n/en.i18n.json) (at handler)

Your application has errors. Waiting for file change.

en.i18n.json:

{
  "pageNotFound": "Page not found!"
}

in case:

{
  "_locale": "en",
  "pageNotFound": "Page not found!"
}

...all work's fine, but you specified in the documentation:

...Other ways file should have name of his locale or be in directory under this name:

Also I noticed that the translation does not pick up the browser locale. Is this fine?

translation file changes not reflected in production?

In my local environment I have two translation files en.i18n.json and zh.i18n.json, they work correctly locally.

But when I push the changes to production server using mup (meteor up), the changes in these translation files don't reflect, they seem to be stuck in an older version.

I tried reloading the browser and clearing all history, doesn't help.

For instance, my {i18n.__('components.home.slogan')} has changed from 'A' to 'B' in a commit. In my local environment it displays 'B'. But when I pushed the code to the production server, everything else updates to the latest, but the translation still shows 'A'.

Meteor 1.4: more examples using classes, mixins, etc.

There should be more examples for ES6/2015 syntax using mixins. For example, what is the equivalent of

import {refreshOnChangeLocaleMixin} from 'meteor/universe:i18n';

export default React.createClass({
    displayName: 'StatsWidget',
    mixins: [refreshOnChangeLocaleMixin],
    /* ... */
});

with declarations such as

import { Component } from 'react';

export default class Foo extends Component {
  render() {
    return <div>Foo</div>
  }
}

Working example code?

Is there a working example of this project anywhere, with at least two languages demonstrating language file use? Seems to be the fastest way to understand how it pieces together.

include emojis in the translations

Does anyone have tried to include emojis inside the translation e.g.

// inside en.i18n.json
{
  "_namespace": "[core]",
  "_locale": "en-EN",
  "emojiText": "hello ${emojify('grinning_face')}"
}

I know a json file is quite limited.

May be running the string through an eval?

Problems with Meteor-1.3-beta.8

Hello, I trying to run package with new Meteor version and I faced with few problems.
First I can't access to i18n via import { i18n } from "meteor/universe:i18n"; but this: import { _i18n } from "meteor/universe:i18n"; works.
Then the translations from files aren't picked up by package. I have two files: en.i18n.json and ru.i18n.json. They were working fine before.

Easy to override options used by the library

So today I noticed this little piece of code in my project:

_i18n.options = {
  open: '[',
  close: ']'
};

I was of course overriding the _i18n.options that are actually used in the library :) - not sure if it's just me, but imo you should either create a setOptions function that makes sure the the default options are still there, or just put the options into _i18n prototype, so that:

_i18n.__proto__.options === options;

this way, even if I were to override _i18n.options, the missing fields would be found in the prototype.

Uncaught ReferenceError: locales is not defined

The error occurs when I try to set the locale for my app on Meteor.startup(...). Precisely, it happens on api.js line 7, trying to get localeName on i18n.loadLocale method.

Does anybody has experienced this issue?

Thanks in advance

Discovery of json/yml of "fr" family doesn't work

Hi,

When I put a file "fr.i18n.yml" into my translation folder, then set the locale to "fr", French language is not loaded. But when I do the same with other locales, as "es", "de", "ru"... it works!

This problem seems to be on all fr-XX family, and is the same with json. I temporarily solved it adding UNIVERSE_I18N_LOCALES = all.

getLang(): not all locales allowed

Hello again,

I have an error in Chomium which shows me the following locales list:

navigator.languages: Array[4]
0: "ru-RU"
1: "ru"
2: "en-US"
3: "en"
error:
screenshot_9

with something like this all works fine:

function getLang() {
    if (navigator.languages != undefined)  {
        if (typeof navigator.languages[0] === 'string') {
            return ~navigator.languages[0].indexOf('-') ?
                navigator.languages[0].replace('-', '_') :
                navigator.languages[0];
        }
    }
...

Thank you!

Thanks so much for this package! I was looking for a reactive solution to use in React, and the TAPi18n package didn't work as well.

multiple _namespace

Hello good evening, as you would to create multiple _namespace in my .i18n.json ?

getLanguages() not returning what is expected

I have currently two supported locales in my app; "en" and "fr". And I want to display a selection of available locales so that the user may switch from the front-end.

By default, "en" is selected when the app start and / or if the user hasn't setup a preferred locale. So, the problem is this :

i18n.getLanguages();
// -> ["en"]

i18n.setLocale('fr');
// -> [Promise]

i18n.getLanguages();
// -> ["en", "fr"]

i18n.setLocale('es');     // no such translation file exists
// -> [Promise]

i18n.getLanguages();
// -> ["en", "fr", "es"]            ???

Is it possible to return all the locales that actually exists and has at least one translation available, at any time? Is it possible not to show locales that has no translations?

isLoaded is true even if translation is not yet loaded.

I have the situation where isLoaded is true, but the translator still returns the default translation (english).

I have this test snippet, that is called somewhere in a container:

console.log(i18n.isLoaded('de'), i18n.getTranslation('my.translation)); // returns true, "english translation"
  i18n.onceChangeLocale(() => {
    console.log(i18n.isLoaded('de'), i18n.getTranslation('my.translation')); // returns true, "german translation"
  }

it's hard to track this down, but i got similar results when using

i18n.setLocale("de").then(function(){
  i18n.getTranslation("my.translation"); // sometimes also returns english translation
});

The promise here should be resolved when the language is ready, but sometimes its resolved earlier.

Cannot find module 'meteor/universe:i18n'.

Hello,

I am trying to use universe:i18n in my Angular2 meteor project. I followed the instructions:
meteor add universe:i18n
import i18n from 'meteor/universe:i18n';

But I keep getting this message: " Cannot find module 'meteor/universe:i18n'. " this the call to i18n.__(key) is successful.

My directory structure is like:
/assets en.i18n.json fr.i18n.json
/client
/server

Even though there are fr and en json files, only en is picked up. I could not figure out why. Please help. Thanks a lot!

My email is: [email protected]

Loading

Sometimes the UI is rendered before the translations (or the translations of a specific language) are loaded. This results in the page being only partially translated.

How do I make sure all translations are loaded before rendering a react component? Can I depend reactively on the translations?

react refreshOnChangeLocaleMixin

Hi!
I'm trying to change locale when user click's on one of the flags (eg english or french)
As I found in docs i have to import "refreshOnChangeLocaleMixin" and then run "i18n.setLocale" on click.
But when I import refreshOnChangeLocaleMixin i have it undefined.
What did I miss? Thanks

import {refreshOnChangeLocaleMixin} from 'meteor/universe:i18n'

console.log(refreshOnChangeLocaleMixin) // returns undefined

C.MainFooter = React.createClass({
  mixins: [refreshOnChangeLocaleMixin],

  handleFlag(value) {
    i18n.setLocale(value, {
      noDownload: true
    })
  },

  render() {
    return (
      <div className="col-xs-12">

          <div className="center footer__flags">
            <img  src="/images/theme/loc_en.png"
                  onClick={this.handleFlag.bind(this, 'en')}/>
            <img  src="/images/theme/loc_fr.png"
                  onClick={this.handleFlag.bind(this, 'fr')}/>
          </div>

      </div>
    )
  }
});

setLocale() facing TypeError: The header content contains invalid characters

I want to get Chinese translation,I got the corresponding translation after setLocale() , but this happened in my console.
image

image

Does it mean my translation files not named correctly?

My translation files are located in i18n/en.i18n.yml, i18n/zh-CN.i18n.yml

in the server

TypeError: The header content contains invalid characters
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:351:13)
    at ServerResponse.res.setHeader (C:\Users\Administrator\AppData\Local\.meteor\packages\webapp\1.3.11\npm\node_modules\connect\lib\patch.js:134:22)
    at ServerResponse.setWriteHeadHeaders (C:\Users\Administrator\AppData\Local\.meteor\packages\webapp\1.3.11\npm\node_modules\on-headers\index.js:82:19)
    at ServerResponse.writeHead (C:\Users\Administrator\AppData\Local\.meteor\packages\webapp\1.3.11\npm\node_modules\on-headers\index.js:41:36)
    at Object.handle (meteor://�app/packages/universe:i18n/server/handler.js:42:17)
    at next (C:\Users\Administrator\AppData\Local\.meteor\packages\webapp\1.3.11\npm\node_modules\connect\lib\proto.js:174:15)
    at Function.app.handle (C:\Users\Administrator\AppData\Local\.meteor\packages\webapp\1.3.11\npm\node_modules\connect\lib\proto.js:182:3)
    at Object.fn [as handle] (C:\Users\Administrator\AppData\Local\.meteor\packages\webapp\1.3.11\npm\node_modules\connect\lib\proto.js:79:14)
    at next (C:\Users\Administrator\AppData\Local\.meteor\packages\webapp\1.3.11\npm\node_modules\connect\lib\proto.js:174:15)
    at Object.WebAppInternals.staticFilesMiddleware (meteor://�app/packages/webapp/webapp_server.js:369:5)

Here are my codes.

main.js

import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import i18n from 'meteor/universe:i18n';
import utils from '../imports/api/utils.js';
import renderRoutes from './routes.jsx';

if (Meteor.isClient) {
  Meteor.startup(() => {
    i18n.setLocale(utils.language());
    render(renderRoutes(), document.getElementById('app'));
  });
}

Forgive my poor English.

getLanguages API

The TAPi18n has an API method, getLanguages, to get the list of languages for which there exist translations. This method is useful to display UI menus to change the language. It doesn’t seem that this package implements a similar method, did I miss something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.