Giter VIP home page Giter VIP logo

i18next-browser-languagedetector's Introduction

Introduction

npm version

This is an i18next language detection plugin used to detect user language in the browser, with support for:

  • cookie (set cookie i18next=LANGUAGE)
  • sessionStorage (set key i18nextLng=LANGUAGE)
  • localStorage (set key i18nextLng=LANGUAGE)
  • navigator (set browser language)
  • querystring (append ?lng=LANGUAGE to URL)
  • htmlTag (add html language tag <html lang="LANGUAGE" ...)
  • path (http://my.site.com/LANGUAGE/...)
  • subdomain (http://LANGUAGE.site.com/...)

Getting started

Source can be loaded via npm, bower or downloaded from this repo.

# npm package
$ npm install i18next-browser-languagedetector

# bower
$ bower install i18next-browser-languagedetector
  • If you don't use a module loader it will be added to window.i18nextBrowserLanguageDetector

Wiring up:

import i18next from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';

i18next.use(LanguageDetector).init({
  supportedLngs: ['de', 'en', 'fr'],
  ...i18nextOptions
});

As with all modules you can either pass the constructor function (class) to the i18next.use or to a concrete instance.

supportedLngs is optional, but allows i18next to pick the best match from the list of detected languages. If it's not set then language will be set to the first detected language, regardless of whether your application has translations for that language or not.

Detector Options

The default options can be found here.

{
  // order and from where user language should be detected
  order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag', 'path', 'subdomain'],

  // keys or params to lookup language from
  lookupQuerystring: 'lng',
  lookupCookie: 'i18next',
  lookupLocalStorage: 'i18nextLng',
  lookupSessionStorage: 'i18nextLng',
  lookupFromPathIndex: 0,
  lookupFromSubdomainIndex: 0,

  // cache user language on
  caches: ['localStorage', 'cookie'],
  excludeCacheFor: ['cimode'], // languages to not persist (cookie, localStorage)

  // optional expiry and domain for set cookie
  cookieMinutes: 10,
  cookieDomain: 'myDomain',

  // optional htmlTag with lang attribute, the default is:
  htmlTag: document.documentElement,

  // optional set cookie options, reference:[MDN Set-Cookie docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie)
  cookieOptions: { path: '/', sameSite: 'strict' },

  // optional conversion function used to modify the detected language code
  convertDetectedLanguage: 'Iso15897',
  convertDetectedLanguage: (lng) => lng.replace('-', '_')
}

Options can be passed in:

preferred - by setting options.detection in i18next.init:

import i18next from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';

i18next.use(LanguageDetector).init({
  detection: options,
});

on construction:

import LanguageDetector from 'i18next-browser-languagedetector';
const languageDetector = new LanguageDetector(null, options);

via calling init:

import LanguageDetector from 'i18next-browser-languagedetector';
const languageDetector = new LanguageDetector();
languageDetector.init(options);

Adding own detection functionality

interface

export default {
  name: 'myDetectorsName',

  lookup(options) {
    // options -> are passed in options
    return 'en';
  },

  cacheUserLanguage(lng, options) {
    // options -> are passed in options
    // lng -> current language, will be called after init and on changeLanguage
    // store it
  },
};

adding it

import LanguageDetector from 'i18next-browser-languagedetector';
const languageDetector = new LanguageDetector();
languageDetector.addDetector(myDetector);

i18next.use(languageDetector).init({
  detection: options,
});

Don't forget: You have to add the name of your detector (myDetectorsName in this case) to the order array in your options object. Without that, your detector won't be used. See the Detector Options section for more.


Gold Sponsors


localization as a service - locize.com

Needing a translation management? Want to edit your translations with an InContext Editor? Use the orginal provided to you by the maintainers of i18next!

locize

With using locize you directly support the future of i18next and react-i18next.


i18next-browser-languagedetector's People

Contributors

adrai avatar dakmor avatar danielsogl avatar dawsbot avatar dcporter44 avatar dennismeeq avatar dependabot[bot] avatar dgmstuart avatar firstred avatar greenkeeperio-bot avatar handbremse avatar jamuhl avatar khownz avatar oxilor avatar pedrodurek avatar perrin4869 avatar pravi avatar robertymb avatar rosskevin avatar simonhype avatar sunflowerfuchs avatar terhuerne avatar totymedli avatar udf2457 avatar vincentlanglet avatar wintondeshong 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

i18next-browser-languagedetector's Issues

I have an issue when I set up detector with cookie

I set up react-i18next with i18next-browser-languagedetector in my project
I set up options as usual setting I think
but it doesn't set up cookie only using local storage
how can I set up cookie value in my project
if i make a wrong setting up options could you give me a some advice for me?

import LngDetector from 'i18next-browser-languagedetector';
...

const options = {
order:['cookie', 'header', 'querystring'],
lookupCookie: 'Locale',
lookupQuerystring: 'Locale',
lookupLocalStorage: 'Locale',

// cookieExpirationDate: new Date(),
caches: ['cookie'],
cookieMinutes: 86400000,
cookieDomain: 'http://localhost:30202',
excludeCacheFor: ['cimode']
}

const detector = new LngDetector(null, options);

i18next
.use(XHR)
.use(detector)
.use(reactI18nextModule)
.init({
debug: true,
interpolation: {
// React already does escaping
escapeValue: false,
},
fallbackLng: 'ko',
lng: 'ko', // 'ko' | 'en',
// localStorageExprirationTime: 86400000,
ns: 'translation',
load:'all',
useCookie: true,
// Using simple hardcoded resources for simple example
resGetPath: 'locales/{{lng}}/{{ns}}.json',
},function(err, t){
window.geoip2.country(onSuccess, onError);
})

Passing the detected language to the app

Hello and sorry if this has already been explained but I couldn't find a proper way to achieve what I want.

I am using this great plugin to detect the user's language in my application, but there are several other things I need to set after detecting the language.

One example is globally setting moment's locale:

moment.locale(detectedLocale);

One more thing would be to store the detected language in the app's redux store:

store.dispatch({ type: 'SET_USER_LOCALE', locale: detectedLocale });

If I try to read it from the i18next.language, as you suggested in #134, the language is not ready when I try to read it (so it returns undefined).

Is there a way to execute/run some code after the language is detected?

Thanks a lot in advance!

Custom detector example

I'm trying to add a detector because I only want to support some languages, for instance British English, but want to detect other english languages like 'en' and 'en-us'. I tried something like the following, but the this seems to have no effect at all. What am I missing? Is there an example of how addDetector should be used?

  const lngDetector = new LanguageDetector()
  lngDetector.addDetector({
    name: 'customDetector',
    cacheUserLanguage(lng, options) {
      debugger
      if (lng.substring(0,2) === 'en')
        localStorage.setItem('i18nextLng', 'en_gb')
      else
        localStorage.setItem('i18nextLng', 'de_de')
    }
  })

  return i18n
   .use(lngDetector)
   .init(options)

Argument of type 'typeof I18nextBrowserLanguageDetector' is not assignable

After upgrading to latest version getting error

Argument of type 'typeof I18nextBrowserLanguageDetector' is not assignable to parameter of type 'BackendModule | LoggerModule | LanguageDetectorModule | LanguageDetectorAsyncModule | I18nFormatModule | ThirdPartyModule[]'.
Type 'typeof I18nextBrowserLanguageDetector' is missing the following properties from type 'ThirdPartyModule[]': pop, push, concat, join, and 25 more.ts(2345)

Will you guys please look into this at earliest
Screenshot 2019-07-31 at 12 57 28 PM

Cant able to change Language which I am sending through query string

I am new to nodejs and i18next, I need to change the language based on user preference, am using node with express template.I used i18next-express-middleware for language detection but i was not successful.Thanks in advance

Server.js

'use strict';

import i18next from 'i18next';
const i18nMiddleware = require('i18next-express-middleware');
import i18nFS from 'i18next-node-fs-backend';
import i18nSprintf from 'i18next-sprintf-postprocessor';
import express from 'express';
import favicon from 'serve-favicon';
import methodOverride from 'method-override';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
import cookieSession from 'cookie-session';
import errorHandler from 'errorhandler';
import passport from 'passport';
import logger from 'winston';
import expressWinston from 'express-winston';
import path from 'path';
import moment from 'moment';
import config from './config';
import routes from './backend/routes';
import db from './backend/models/db';

// Init locale
i18next.use(i18nMiddleware.LanguageDetector)
.use(i18nFS)
.use(i18nSprintf)
.init({
debug: false,
fallbackLng: 'en',
pluralSeparator: '_',
keySeparator: '::',
nsSeparator: ':::',
detection: {
order: [ /'path', 'session',/ 'querystring', 'cookie', 'header'],
lookupQuerystring: 'lng',
lookupPath: 'lng',
lookupCookie: 'locaI18next',
cookieDomain: 'loca',
caches: ['cookie']
},
backend: {
loadPath: path.join(dist_directory, 'locales', '{{lng}}.json')
}
});

// Init express
const app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(cookieParser());
app.use(cookieSession({
secret: 'loca-secret',
cookie: {
maxAge: 3600000
}
}));
app.use(i18nMiddleware.handle(i18next));
app.use(function(req, res, next) {
var splitedLanguage = req.language.split('-');
moment.locale(splitedLanguage[0]);
next();
});

// Init routes
routes.forEach(route => {
app.use(route());
});
app.use(errorHandler());
logger.info('In development mode (no minify/no uglify)');
}
db.init();
const http_port = process.env.LOCA_NODEJS_PORT || 8081;
app.listen(http_port, function() {
logger.info('Listening port ' + http_port);
if (debugMode) {
const LiveReloadServer = require('live-reload');
LiveReloadServer({
_: ['dist'],
port: 9091
});
}
});

Router.js
router.get('/accounts',function(req, res){
req.i18n.changeLanguage(req.query.lng);
});

Kindly excuse me if I made some blunders, your help is really appreciated.

Exclude Cache for querystring

What value do I pass excludeCacheFor so that if the language is detected through querystring it's not stored as a cookie? I only see cimode as an example in the docs. Would be nice to expand on this so it's more clear on how to utilize this feature :)

Options is missing custom getCookie and setCookie

How i18next-browser-languageDetector is able to get and set cookies on an express server?
I would like to have your opinion for a PR that adds getCookie and setCookie options to this package so I can store and retrieve user preferred language on server as well.

setup similar language use one language

Hi
i have two folders(zh and en) to store language data, and i18next-browser-languageDetector detect language may be 'zh', 'zh-CN', 'zh-TW', 'en', 'en-US' etc
i want the chinese('zh','zh-CN' etc) use data in folder 'zh' and english('en', 'en-US' etc) use data in folder 'en'.
but i don't know how to set i18next to satisfy my demand, could you tell me how to do this.
thanks.

I still have some issues to understand the plugin.

Hi,

my idea is:

  1. If the user opens my website, than there is no information, so I have to detect the browser language, and translate the website in the detected language.

  2. Now I know the language, so on the next page I don't need to detect the language from the browser, I need to use the language which was used one page before.

How can I solve this out?

Thanks,
Christian.

I have an issue to set up cookie

I set up react-i18next with i18next-browser-languagedetector in my project
I set up options as usual setting I think
but it doesn't set up cookie only using local storage
how can I set up cookie value in my project
if i make a wrong setting up options could you give me a some advice for me?

import LngDetector from 'i18next-browser-languagedetector';
...

const options = {
order:['cookie', 'header', 'querystring'],
lookupCookie: 'Locale',
lookupQuerystring: 'Locale',
lookupLocalStorage: 'Locale',

// cookieExpirationDate: new Date(),
caches: ['cookie'],
cookieMinutes: 86400000,
cookieDomain: 'http://localhost:30202',
excludeCacheFor: ['cimode']

}

const detector = new LngDetector(null, options);

i18next
.use(XHR)
.use(detector)
.use(reactI18nextModule)
.init({
debug: true,
interpolation: {
// React already does escaping
escapeValue: false,
},
fallbackLng: 'ko',
lng: 'ko', // 'ko' | 'en',
// localStorageExprirationTime: 86400000,
ns: 'translation',
load:'all',
useCookie: true,
// Using simple hardcoded resources for simple example
resGetPath: 'locales/{{lng}}/{{ns}}.json',
},function(err, t){
window.geoip2.country(onSuccess, onError);
})

cannot import into rollup bundle

In rollup, this fails:

import lngDetector from 'i18next-browser-languagedetector';

Here's the error:

Module /Users/.../node_modules/i18next-browser-languagedetector/dist/es/index.js does not export default (imported by /Users/.../public/src/index.js)

Async Custom Language Detector

Is it possible to have an asynchronous custom language detector? I need to call out to an API to get the user's stored locale preference, but since this is an async call, the value returned from my lookup function is null because the Promise returned from the API doesn't resolve until after the lookup call has completed. For now, I'm just calling the API directly and then calling i18n.changeLanguage once the Promise resolves (and not using a custom detector), but this causes the screen to flash briefly with my default language on first load. Any suggestions on how to work around this?

Fallback language not found with specific fallbackLng option

Hello,

We are using a specific 'fallbackLng' configuration which looks like this

i18next.init({ fallbackLng: { 'de-CH': ['fr', 'it'], 'zh-HANT': ['zh-HANS', 'en'], 'es': ['fr'], 'default': ['en'] } });

This configuration should be supported as mentioned in the official i18n documentation : https://www.i18next.com/principles/fallback.html

But when I look at the code (see below), this specific configurations does not seem to be supported

return found || this.i18nOptions.fallbackLng[0];

In my case, this specific line should be

return found || this.i18nOptions.fallbackLng[0] || this.i18nOptions.fallbackLng['default'];

Is there any way we can support this?

Thank you very much

Feature Request: Allow lookup from path to look at two parts of the path

As the code is right now, lookupFromPathIndex can only be one number.

If I have a URL that breaks the locale up into two parts such as /en/us/restOfPath, then I can only grab the language portion of the path. I want to be able to construct the full locale en-US from the path and not just the 'en' portion.

s.languageDetector.init is not a function

Using i18next 3.4.1/i18next-browser-languageDetector 1.0.0 with typescript/webpack

Building using typescript/webpack, a webpack build completes without errors. Loading the (Aurelia) application in a browser gives the following error:

bluebird.js:5119TypeError: s.languageDetector.init is not a function
    at I18n.init (http://localhost:9000/app.bundle.js:3410:28)
    at http://localhost:9000/app.bundle.js:37447:63
    at registerI18N (http://localhost:9000/app.bundle.js:24583:13)
    at Object.configure (http://localhost:9000/app.bundle.js:24645:26)
    at http://localhost:9000/aurelia.bundle.js:12891:34
From previous event:
    at _loadPlugin (http://localhost:9000/aurelia.bundle.js:12889:40)
    at http://localhost:9000/aurelia.bundle.js:12882:14
From previous event:
    at loadPlugin (http://localhost:9000/aurelia.bundle.js:12881:73)
    at next (http://localhost:9000/aurelia.bundle.js:13142:18)
From previous event:
    at next (http://localhost:9000/aurelia.bundle.js:13142:54)
    at http://localhost:9000/aurelia.bundle.js:13149:14
From previous event:
    at FrameworkConfiguration.apply (http://localhost:9000/aurelia.bundle.js:13134:42)
    at Aurelia.start (http://localhost:9000/aurelia.bundle.js:12751:21)
    at Object._callee$ (http://localhost:9000/app.bundle.js:37479:40)
    at tryCatch (http://localhost:9000/aurelia-bootstrap.bundle.js:3189:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (http://localhost:9000/aurelia-bootstrap.bundle.js:3463:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (http://localhost:9000/aurelia-bootstrap.bundle.js:3222:21)
    at http://localhost:9000/app.bundle.js:37390:65
From previous event:
    at __awaiter (http://localhost:9000/app.bundle.js:37370:12)
    at Object.configure (http://localhost:9000/app.bundle.js:37413:12)
    at http://localhost:9000/aurelia-bootstrap.bundle.js:15254:27
From previous event:
    at config (http://localhost:9000/aurelia-bootstrap.bundle.js:15253:46)
    at handleApp (http://localhost:9000/aurelia-bootstrap.bundle.js:15244:10)
    at http://localhost:9000/aurelia-bootstrap.bundle.js:15272:9
From previous event:
    at http://localhost:9000/aurelia-bootstrap.bundle.js:15269:44
From previous event:
    at run (http://localhost:9000/aurelia-bootstrap.bundle.js:15266:24)
    at Object.<anonymous> (http://localhost:9000/aurelia-bootstrap.bundle.js:15291:1)
    at Object.aurelia-bootstrapper-webpack (http://localhost:9000/aurelia-bootstrap.bundle.js:15292:30)
    at __webpack_require__ (http://localhost:9000/aurelia-bootstrap.bundle.js:57:38)
    at Object.184 (http://localhost:9000/aurelia-bootstrap.bundle.js:7252:1)
    at __webpack_require__ (http://localhost:9000/aurelia-bootstrap.bundle.js:57:38)
    at 0 (http://localhost:9000/aurelia-bootstrap.bundle.js:140:18)
    at http://localhost:9000/aurelia-bootstrap.bundle.js:143:10

detect language

Hello

I have this code

import LanguageDetector from 'i18next-browser-languagedetector';


function getLanguage () {
    const i18n = localStorage.getItem('i18nextLng') && localStorage.getItem('i18nextLng').indexOf('pt') != -1
        ? require('./locales/pt/i18n').default
        : require('./locales/es/i18n').default
    return i18n;
}

export default getLanguage();

wich is a call to a different files es or pt
how can i detect language witho being with localStorage.getItem('i18nextLng')
because on start application i got an error....

can someone help me on this
i want two differente files i18n configuration for each language

import { I18nextProvider } from 'react-i18next';
import i18n from '../../i18n';

many thanks carlos vieira

Detection via subdomain ignores the first subdomain.

EDIT: derp. Forgot about how normal urls are structured...
v3.0.0 and current master
The examples below use a line of code from /src/browserLookups/subdomain.js

window.location.href = http://es.localhost:3000/
var language = window.location.href.match(/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/gi);
// language is null
window.location.href = http://en.es.localhost:3000/
var language = window.location.href.match(/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/gi);
// language is [http://en].

I wish I knew regex well enough to provide a fix.

Webpack warning

Similar to this issue: i18next/i18next#477

When i18next-browser-languageDetector is loaded via Webpack, the following warning appears:

./~/i18next-browser-languagedetector/bin/index.js
Critical dependencies:
1:432-439 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
 @ ./~/i18next-browser-languagedetector/bin/index.js 1:432-439

Would it be possible to apply the same fix as in i18next issue 477?

Configure routes when using path detection

I can make the app choose the correct language based on the language specified on the path. Exmple: localhost:3000/en/home or localhost:3000/es/home. My problem is that /home route is not recognize and a 404 is rendered. What is the correct way to configure this? and what if I want to be localhost:3000/home (en) and localhost:3000/es (spanish)?

Cache invalidation

How to invalidate the local storage cache?

My user accessed the app before I added their browser's default language. Now they see English instead of French.

browser crash in chrome incognito window

i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
...
});

It seems chrome incognito window will keep loading constantly and make the browser crash.

Safari 10: SecurityError (DOM Exception 18): The operation is insecure.

If Safari 10 does not allow access to the local storage this error is thrown: "SecurityError (DOM Exception 18): The operation is insecure".

This happens because of these lines:

https://github.com/i18next/i18next-browser-languageDetector/blob/master/src/browserLookups/localStorage.js#L29

https://github.com/i18next/i18next-browser-languageDetector/blob/master/src/browserLookups/localStorage.js#L38

Safari already throws this error if you access "window.localStorage".

Thanks! :-)

`cacheUserLanguage` is not being called after init or on the `changeLanguage` event in a custom language detector

I'm trying to attach a custom language detector so I can cache the user language in Redux but it doesn't seem like my cacheUserLanguage event callback is ever getting triggered, though my initial lookup callback is.

Here's the relevant code:

const hxsbDetector = {
    name: 'hxsbDetector',
    lookup(options: DetectLanguage.DetectorOptions) {
        let browserLangCode = window.navigator.userLanguage ?
            window.navigator.userLanguage :window.navigator.language;        
        
        return browserLangCode;
    },
    cacheUserLanguage(lang, options) {
        // lang -> current language, will be called after init and on changeLanguage
        console.log('Hello from cacheUserLanguage! Language is %s', lang);
        // Add to redux here
      }
}

const languageDetector = new DetectLanguage(); 
languageDetector.addDetector(hxsbDetector);

const I18n = i18next
    .use(languageDetector)
    .init({
        detection: {
            order: ['hxsbDetector', 'navigator']
        },
       ...
});

Is there something else I'm missing?

browser user preference not use correcly

Hello

I want to report an issue that I'm facing. If I'm wrong, don't hesitate to correct me; I may have miss something in my understanding of how languageDetector works.

Here is my i18n configuration:

import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-xhr-backend';
i18n
  .use(Backend)
  .use(LanguageDetector)
	.init({
		fallbackLng: 'en',

		// have a common namespace used around the full app
		ns: ['common'],
		defaultNS: 'common',

		debug: true,
		backend: {
			loadPath: '/src/i18n/{{lng}}/{{ns}}.json'
		},

		interpolation: {
			escapeValue: false, // not needed for react!!
			formatSeparator: ',',
			format: (value, format, lng) => {
				if (format === 'uppercase') return value.toUpperCase();
				return value;
			}
		}
	});

Here is my chrome configuration:
image

As you can see, I'm french (my default chrome configuration) but prefer to work in English. I have added the English language and set it as "to use as default":

image

When loading my site the first time (no local storage of any kind), navigator.js will load the navigator languages settings:

image

Then will load the chosen preferred language. Chrome set, in the variable navigator.language, the language I have chosen as default:

image

As a result, here is the lookup (from index.js):

image

My problem is in the next loop to find the "found" language: The first element in the array is used as found. Therefore, the user preferred language, that was put at the end of all other navigator defined languages, is never used.

I believe that the user preferred language should have a higher priority than other defined language:
Could we change line:
found.push(navigator.language);
into:
found.unshift(navigator.language);
This way, it will be used first.

Let me know if I miss the point of if there is a solution for my problem.

I can pull a request if you want.

Thank you

Validate language

Since the querystring can be modified by a user, the plugin should validate if the detection is a valid language. If the language is not valid, we should go to the next detector.

How about onlyLang settings

I need in only a lang, without region. Example: en-EN -> en, fr-FR -> fr.
How i can do it?

I think need add setting onlyLang. If this setting is true, then return only lang.

Thanks for answer.

define function is incorrect

Line 3 of i18nextBrowserLanguageDetector.js in the bower package is incorrect. It currently reads typeof define === 'function' && define.amd ? define('i18nextBrowserLanguageDetector', factory) : when it should be typeof define === 'function' && define.amd ? define(factory) :. This causes LngDetector to be undefined when required.

Question: Possible to override language list?

Apologies, I can't find an issue for this (or a better place to ask).

TLDR; I want to reduce the number of HTTP requests sent to my server by i18n-next, when it looks for the locale json file(s) to use.

Details...
This lib tries to resolve country specific variants of a language first, before defaulting to the standard definition. I.e en-GB or en-US are attempted first, followed by en. In my app, I will never have country specific variants, so requests looking for these locale file variants are wasteful and cause jank within my react views on slow bandwidth networks. Is it possible to configure this lib to resolve en-GB and en-US as en and never check the server for the country specific variants?

Language Detector fails on iOS Device

I've setted up i18next along with the language detector plugin on my website.

i18nextOptions = {
                          load:['en', 'de'],
                          whitelist:['en', 'de'],
                          fallbackLng: 'en',
                          backend: {loadPath: './locales/{{lng}}.json', addPath: './locales/add/{{lng}}.json'},
                          detection: {order: ['querystring', 'cookie', 'navigator', 'localStorage'],
                                      lookupQuerystring: 'lng',
                                      lookupCookie: 'i18next',
                                      lookupLocalStorage: 'i18nextLng',
                                      caches: ['localStorage', 'cookie'],
                                      cookieMinutes: 5},
                          debug: false
                         };
i18next
      .use(window.i18nextXHRBackend)
      .use(window.i18nextBrowserLanguageDetector)
      .init(i18nextOptions, function (err, t) {

Evertything is working fine except for iOS Devices. If you open my website on an iOS Device with German language, the website always appears in English. Does anyone know why? Will be greatful for any help.

THX

Navigator browser lookup does not return only the language

Hello! :-),

The navigator browser lookup does not consider the i18next configuration option load: languageOnly. If the navigator has following languages ['en-US', 'en'] the i18next language (i18next.language) will be en-US and not only en.

Is this an i18next issue or an issue of this library?

Thanks!

All supported languages

I need the list of supported languages for my app's purposes. The Detector plugin does all the necessary job in the detect method, but then it just uses the first available entry, so the rest is lost.

It would be cool to extract the part that compiles the list of languages into a separate function if this information cannot be retrieved by other means.

I would be happy to submit a PR if you don't object.

Bug: Looking for subdomain in pathname

LanguageDetector searching for subdomain inside a pathname, in the i18nextBrowserLanguageDetector.js[190:0].

var language = window.location.pathname.match(/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/gi);

I assume this regex should be executed on origin or href instead, right?

queryString lookupQueryString not picking up custom value

detection: { // Settings for language detector
order: ['querystring', 'cookie', 'navigator'],
lookupQueryString: 'langPref',
lookupCookie: 'myCookie',
caches: ['cookie'],
cookieMinutes: 525600
}

Doesn't look like setting lookupQueryString actually works.

localhost:3000/?langPref=ja (Doesn't Work)

localhost:3000/?lng=ja (Works!)

I would expect the first one to work since I set lookupQueryString: 'langPref'

TypeError: props.i18n.changeLanguage is not a function

I've updated to i18next": "^13.0.0 and started to get this error... not sure if it's a languageDetector or i18next-react issue?

TypeError: props.i18n.changeLanguage is not a function
initSSR
node_modules/react-i18next/dist/es/utils.js:46
  43 |   }
  44 | 
  45 |   if (!initializedLanguageOnce && props.initialLanguage) {
> 46 |     props.i18n.changeLanguage(props.initialLanguage);
  47 |     initializedLanguageOnce = true;
  48 |   }
  49 | } // --------------

using typescript: 3.2.2

language not detected in 0.2.0

Just putting this here already but will try to find out more.

In version 0.2.0 the browser language is not detected (i18next.language is undefined) under certain conditions (in Enketo I only seem to be able to reproduce it in offline-capable pages, were all resources are loaded from the applicationCache - seems weird). The issue occurs after i18next was initialized.

Version 0.1.0 did not have that problem. It might also be a compatibility issue with i18next v 2.2.x as I haven't updated that one yet (due to an issue).

Language not detected from navigator

I have the following i18n config which was taken from this react SSR example

Language pref continues to be stored in localStorage though I read docs that indicate the excludeCacheFor should disable that and it doesn't update on refresh if the browser language preference (in the navigator) changes. Please help! I've tried many alterations (including putting the order in a detection prop. Any advice is greatly appreciated!

import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import XHR from 'i18next-xhr-backend'
import LanguageDetector from 'i18next-browser-languagedetector'

const options = {
  fallbackLng: 'en',
  ns: ['translations'],
  defaultNS: 'translations',
  order: ['navigator'],
  debug: true,
  caches: [],
  excludeCacheFor: ['cimode'],
  interpolation: {
    escapeValue: false, // not needed for react!!
    formatSeparator: ',',
    format: (value, format, lng) => {
      if (format === 'uppercase') return value.toUpperCase()
      return value
    },
  },
  react: {
    useSuspense: false,
  },
  detection: {
    order: ['navigator', 'cookie'],
  },
  wait: process && !process.release,
}

if (process && !process.release) {
  i18n
    .use(XHR)
    .use(initReactI18next)
    .use(LanguageDetector)
}

if (!i18n.isInitialized) {
  i18n.init(options)
}

export default i18n

Should we check i18next languageOnly option?

`{
key: 'detect',
value: function detect(detectionOrder) {
var _this = this;

    if (!detectionOrder) detectionOrder = this.options.order;

    var detected = [];
    detectionOrder.forEach(function (detectorName) {
      if (_this.detectors[detectorName]) {
        var lookup = _this.detectors[detectorName].lookup(_this.options);
        if (lookup && typeof lookup === 'string') lookup = [lookup];
        if (lookup) detected = detected.concat(lookup);
      }
    });

    var found = void 0;
    detected.forEach(function (lng) {
      if (found) return;
      var cleanedLng = _this.services.languageUtils.formatLanguageCode(lng);
     if (_this.i18nOptions.load === 'languageOnly') cleanedLng = _this.services.languageUtils.getLanguagePartFromCode(cleanedLng);
      if (_this.services.languageUtils.isWhitelisted(cleanedLng)) found = cleanedLng;
    });

    return found || this.i18nOptions.fallbackLng[0];
  }
}`

What do you think about the bold part? Should we add it?
if (_this.i18nOptions.load === 'languageOnly') cleanedLng = _this.services.languageUtils.getLanguagePartFromCode(cleanedLng);

TypeError: detectionOrder.forEach is not a function

I'm trying to use the SSR feature of i18next and running into issues. I'm trying to detect the language based on the request and getting the current error TypeError: detectionOrder.forEach is not a function

here is my setup.

Server:

import express from 'express'
import i18n from './i18n'
import i18nMiddleware from 'i18next-express-middleware'

const app = express()
const PORT = process.env.PORT || 3000

app.use(i18nMiddleware.handle(i18n));

i18n instance on server:

import i18n from 'i18next'
import Backend from 'i18next-node-fs-backend'
import { LanguageDetector } from 'i18next-express-middleware'

i18n
  .use(Backend)
  .use(LanguageDetector)
  .init({
    fallbackLng: 'en',
    nsSeparator: false,
    debug: true,
    backend: {
      loadPath: 'public/locales/{{lng}}.json',
    },
  })

export default i18n

Then in the server I'm cloning the i18n from the client and changing lang based on the request

let useri18n = i18n.cloneInstance()
      useri18n.changeLanguage(req.language)

      frontloadServerRender(() => renderToString(
        <Loadable.Capture report={m => modules.push(m)}>
          <I18nextProvider i18n={useri18n}>
            <StaticRouter location={req.url} context={context}>
              <Frontload>
                <App/>
              </Frontload>
            </StaticRouter>
          </I18nextProvider>
        </Loadable.Capture>,

...more code

Then on the client:

const App = () => (
  <I18nextProvider i18n={i18n}>
    <ThemeProvider theme={theme}>
      <AuthProvider>
        <Route path="/" component={Main} />
      </AuthProvider>
    </ThemeProvider>
  </I18nextProvider>
)

i18n on client:

import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import Backend from 'i18next-node-fs-backend'
import LanguageDetector from 'i18next-browser-languagedetector'

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    fallbackLng: 'en',
    debug: true,
    wait: true,
    detection: {
      order: ['navigator', 'localStorage'],
    },
  })

Error says it's coming from i18next-browser-languagedetector/dist/commonjs/index.js:109:22. When I console log detectionOrder in there it's an object that looks like this:

IncomingMessage {
  _readableState:
   ReadableState {
     objectMode: false,
     highWaterMark: 16384,
     buffer: BufferList { length: 0 },
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: null,
     ended: false,
     endEmitted: false,
     reading: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     resumeScheduled: false,
     emitClose: true,
     destroyed: false,
     defaultEncoding: 'utf8',
     awaitDrain: 0,
     readingMore: true,
     decoder: null,
     encoding: null },
  readable: true,
  _events: {},
  _eventsCount: 0,
  _maxListeners: undefined,
  socket:
   Socket {
     connecting: false,
     _hadError: false,
     _handle:
      TCP {
        reading: true,
        owner: [Circular],
        onread: [Function: onread],
        onconnection: null,
        _consumed: true },
     _parent: null,
     _host: null,
     _readableState:
      ReadableState {
        objectMode: false,
        highWaterMark: 16384,
        buffer: BufferList { length: 0 },
        length: 0,
        pipes: null,
        pipesCount: 0,
        flowing: true,
        ended: false,
        endEmitted: false,
        reading: true,
        sync: false,
        needReadable: true,
        emittedReadable: false,
        readableListening: false,
        resumeScheduled: false,
        emitClose: false,
        destroyed: false,
        defaultEncoding: 'utf8',
        awaitDrain: 0,
        readingMore: false,
        decoder: null,
        encoding: null },
     readable: true,
     _events:
      { end: [Array],
        drain: [Array],
        timeout: [Function: socketOnTimeout],
        data: [Function: bound socketOnData],
        error: [Function: socketOnError],
        close: [Array],
        resume: [Function: onSocketResume],
        pause: [Function: onSocketPause] },
     _eventsCount: 8,
     _maxListeners: undefined,
     _writableState:
      WritableState {
        objectMode: false,
        highWaterMark: 16384,
        finalCalled: false,
        needDrain: false,
        ending: false,
        ended: false,
        finished: false,
        destroyed: false,
        decodeStrings: false,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        corked: 0,
        sync: false,
        bufferProcessing: false,
        onwrite: [Function: bound onwrite],
        writecb: null,
        writelen: 0,
        bufferedRequest: null,
        lastBufferedRequest: null,
        pendingcb: 0,
        prefinished: false,
        errorEmitted: false,
        emitClose: false,
        bufferedRequestCount: 0,
        corkedRequestsFree: [Object] },
     writable: true,
     allowHalfOpen: true,
     _sockname: null,
     _pendingData: null,
     _pendingEncoding: '',
     server:
      Server {
        _events: [Object],
        _eventsCount: 2,
        _maxListeners: undefined,
        _connections: 2,
        _handle: [TCP],
        _usingWorkers: false,
        _workers: [],
        _unref: false,
        allowHalfOpen: true,
        pauseOnConnect: false,
        httpAllowHalfOpen: false,
        timeout: 120000,
        keepAliveTimeout: 5000,
        _pendingResponseData: 0,
        maxHeadersCount: null,
        _connectionKey: '6::::3000',
        [Symbol(IncomingMessage)]: [Function],
        [Symbol(ServerResponse)]: [Function],
        [Symbol(asyncId)]: 11 },
     _server:
      Server {
        _events: [Object],
        _eventsCount: 2,
        _maxListeners: undefined,
        _connections: 2,
        _handle: [TCP],
        _usingWorkers: false,
        _workers: [],
        _unref: false,
        allowHalfOpen: true,
        pauseOnConnect: false,
        httpAllowHalfOpen: false,
        timeout: 120000,
        keepAliveTimeout: 5000,
        _pendingResponseData: 0,
        maxHeadersCount: null,
        _connectionKey: '6::::3000',
        [Symbol(IncomingMessage)]: [Function],
        [Symbol(ServerResponse)]: [Function],
        [Symbol(asyncId)]: 11 },
     timeout: 120000,
     parser:
      HTTPParser {
        '0': [Function: parserOnHeaders],
        '1': [Function: parserOnHeadersComplete],
        '2': [Function: parserOnBody],
        '3': [Function: parserOnMessageComplete],
        '4': [Function: bound onParserExecute],
        _headers: [],
        _url: '',
        _consumed: true,
        socket: [Circular],
        incoming: [Circular],
        outgoing: null,
        maxHeaderPairs: 2000,
        onIncoming: [Function: bound parserOnIncoming] },
     on: [Function: socketOnWrap],
     _paused: false,
     _httpMessage:
      ServerResponse {
        _events: [Object],
        _eventsCount: 1,
        _maxListeners: undefined,
        output: [],
        outputEncodings: [],
        outputCallbacks: [],
        outputSize: 0,
        writable: true,
        _last: false,
        chunkedEncoding: false,
        shouldKeepAlive: true,
        useChunkedEncodingByDefault: true,
        sendDate: true,
        _removedConnection: false,
        _removedContLen: false,
        _removedTE: false,
        _contentLength: null,
        _hasBody: true,
        _trailer: '',
        finished: false,
        _headerSent: false,
        socket: [Circular],
        connection: [Circular],
        _header: null,
        _onPendingData: [Function: bound updateOutgoingData],
        _sent100: false,
        _expect_continue: false,
        req: [Circular],
  
.....

Any ideas on why this is happening? I'm assuming I'm doing something wrong but am lost at this point and appreciate any advice someone can give!

Thanks in advance.

i18next-browser-languageDetector not working on IE 11

This is my code in i18n.js. It is working fine for all other browsers except for IE. In IE it is always returned as English. Am I doing any thing wrong here?

Thanks

import i18n from 'i18next';
import XHR from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';

var options = {
// order and from where user language should be detected
order: ['navigator', 'querystring', 'cookie', 'localStorage', 'htmlTag'],

// keys or params to lookup language from
lookupQuerystring: 'lng',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',

// cache user language on
caches: ['localStorage', 'cookie'],

// optional expire and domain for set cookie
cookieMinutes: 10,
cookieDomain: '.lab.net',

// optional htmlTag with lang attribute, the default is:
htmlTag: document.documentElement
}

i18n
.use(XHR)
.use(LanguageDetector)
.init({
detection: options,
whitelist: ['en', 'da', 'de', 'el', 'fi','fil', 'tl', 'fr','hi','id','it','ja',
'ko','mr','ms','nl','no','pl','pt-BR','ru','sv','ta','th','tr','uk','vi',
'zh','zh-TW','da-DK','de-DE','el-GR','fi-FI','fr-FR','hi-IN','it-IT', 'ja-JP',
'ko-KR', 'nl-NL', 'nb-NO','pl-PL', 'ru-RU','sv-SE', 'th-TH', 'uk-UA','vi-VN','es-XL', ],
fallbackLng: 'en',
// have a common namespace used around the full app
ns: ['common'],
defaultNS: 'common',
//debug: true,
interpolation: {
escapeValue: false // not needed for react!!
},
loadPath: '/locales/{{lng}}/{{ns}}.json',
});

export default i18n;

Why is en loaded when de is specified in url?

This is more of an optimization request I suppose. I was trying out the language detector and wanted to see the lng=de in action. I was surprised to see that the en was loaded before the de. The de strings were used correctly. I would rather the code not waste it's time loading the en strings when they are not going to be used.

Also, some example say show .use(LanguageDetector) and other .use(LngDetector).

image

Can't get language detection to work properly

Hi,

This is my init file:

{
    whitelist: ['zh', 'en', 'zh-HK', 'zh-TW',],
    fallbackLng: false,
    preload: ['zh', 'en', 'zh-HK', 'zh-TW',],
    ns: ['translations'],
    defaultNS: 'translations',
    nonExplicitWhitelist: true,
    detection: {
    caches: [],
    cookieMinutes: 1,
}

I've been trying for a few days to get this to work, but I haven't had any luck. When I changed Chrome's display language, I would always get 'en'. If I disabled 'en' from the whitelist, I would get my preference of 'zh-TW' to become 'zh-CN', or some other bugs. If I keep 'en' in the whitelist, I would always get 'en' as my language, regardless of what language I set in the browser.

Also during my testing, I would always have to clear my cookies because I think the caching is ruining my testing. Its why sometimes I get inconsistent results I believe.

Does someone have any working init settings to work with English and Chinese?

Thanks

Edit1:
In another recent test: I have detected the language zh-TW but somehow the i18next.language is en

Edit2:
If I renamed my en folder to something other than en, e.g: en22, and if I remove 'en' from my init settings I get these errors:

GET http://localhost:8080/assets/locales/en/translations.json 404 (Not Found)
Error: ["failed loading /assets/locales/en/translations.json"]

I find it very weird that even with no reference to 'en' anywhere in my code, i18next still tries to look for en. I believe it is caused by this log: i18next: languageChanged en. So I'm believing that there is something wrong with the language detector, just defaulting to en all the time (In this scenario, my browser's language is set to zh-TW).

TypeError: Cannot read property 'languageUtils' of undefined

I have been struggling for a while to get the languageDetector working.

I am making a web application using Aurelia..
At startup, I was invoking the Language Detection exactly as described here in the
documentation, but the application always returned a:

TypeError: Cannot read property 'languageUtils' of undefined,

caused by i18nextBrowserLanguageDetector.js, line 258:
"var cleanedLng = _this.services.languageUtils.formatLanguageCode(lng);"

An analysis showed me that this invocation happens within the Browser function that gets
constructed using a services reference, and I didn't manage to find out how on earth
that reference gets passed to the Browser function, when implementing according to the
documentation..

Constructing the LngDetector with a reference to i18next.services solves the problem,
I may be mistaken in something, and I'd love to understand what that could be,
or perhaps its just the documentation that needs to be updated?

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.