Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
E
ecommerce-ui
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
ecommerce-ui
Commits
7b638c81
Commit
7b638c81
authored
Dec 13, 2013
by
Sven Franck
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added i18next plugin for i18n
parent
ec687a76
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
2662 additions
and
0 deletions
+2662
-0
js/plugins/i18next/i18next.js
js/plugins/i18next/i18next.js
+2662
-0
No files found.
js/plugins/i18next/i18next.js
0 → 100644
View file @
7b638c81
// i18next, v1.7.1
// Copyright (c)2013 Jan Mühlemann (jamuhl).
// Distributed under MIT license
// http://i18next.com
(
function
()
{
// add indexOf to non ECMA-262 standard compliant browsers
if
(
!
Array
.
prototype
.
indexOf
)
{
Array
.
prototype
.
indexOf
=
function
(
searchElement
/*, fromIndex */
)
{
"
use strict
"
;
if
(
this
==
null
)
{
throw
new
TypeError
();
}
var
t
=
Object
(
this
);
var
len
=
t
.
length
>>>
0
;
if
(
len
===
0
)
{
return
-
1
;
}
var
n
=
0
;
if
(
arguments
.
length
>
0
)
{
n
=
Number
(
arguments
[
1
]);
if
(
n
!=
n
)
{
// shortcut for verifying if it's NaN
n
=
0
;
}
else
if
(
n
!=
0
&&
n
!=
Infinity
&&
n
!=
-
Infinity
)
{
n
=
(
n
>
0
||
-
1
)
*
Math
.
floor
(
Math
.
abs
(
n
));
}
}
if
(
n
>=
len
)
{
return
-
1
;
}
var
k
=
n
>=
0
?
n
:
Math
.
max
(
len
-
Math
.
abs
(
n
),
0
);
for
(;
k
<
len
;
k
++
)
{
if
(
k
in
t
&&
t
[
k
]
===
searchElement
)
{
return
k
;
}
}
return
-
1
;
}
}
// add lastIndexOf to non ECMA-262 standard compliant browsers
if
(
!
Array
.
prototype
.
lastIndexOf
)
{
Array
.
prototype
.
lastIndexOf
=
function
(
searchElement
/*, fromIndex*/
)
{
"
use strict
"
;
if
(
this
==
null
)
{
throw
new
TypeError
();
}
var
t
=
Object
(
this
);
var
len
=
t
.
length
>>>
0
;
if
(
len
===
0
)
{
return
-
1
;
}
var
n
=
len
;
if
(
arguments
.
length
>
1
)
{
n
=
Number
(
arguments
[
1
]);
if
(
n
!=
n
)
{
n
=
0
;
}
else
if
(
n
!=
0
&&
n
!=
(
1
/
0
)
&&
n
!=
-
(
1
/
0
))
{
n
=
(
n
>
0
||
-
1
)
*
Math
.
floor
(
Math
.
abs
(
n
));
}
}
var
k
=
n
>=
0
?
Math
.
min
(
n
,
len
-
1
)
:
len
-
Math
.
abs
(
n
);
for
(;
k
>=
0
;
k
--
)
{
if
(
k
in
t
&&
t
[
k
]
===
searchElement
)
{
return
k
;
}
}
return
-
1
;
};
}
var
root
=
this
,
$
=
root
.
jQuery
||
root
.
Zepto
,
i18n
=
{}
,
resStore
=
{}
,
currentLng
,
replacementCounter
=
0
,
languages
=
[]
,
initialized
=
false
;
// Export the i18next object for **CommonJS**.
// If we're not in CommonJS, add `i18n` to the
// global object or to jquery.
if
(
typeof
module
!==
'
undefined
'
&&
module
.
exports
)
{
module
.
exports
=
i18n
;
}
else
{
if
(
$
)
{
$
.
i18n
=
$
.
i18n
||
i18n
;
}
root
.
i18n
=
root
.
i18n
||
i18n
;
}
// defaults
var
o
=
{
lng
:
undefined
,
load
:
'
all
'
,
preload
:
[],
lowerCaseLng
:
false
,
returnObjectTrees
:
false
,
fallbackLng
:
'
dev
'
,
fallbackNS
:
[],
detectLngQS
:
'
setLng
'
,
ns
:
'
translation
'
,
fallbackOnNull
:
true
,
fallbackToDefaultNS
:
false
,
nsseparator
:
'
:
'
,
keyseparator
:
'
.
'
,
selectorAttr
:
'
data-i18n
'
,
debug
:
false
,
resGetPath
:
'
locales/__lng__/__ns__.json
'
,
resPostPath
:
'
locales/add/__lng__/__ns__
'
,
getAsync
:
true
,
postAsync
:
true
,
resStore
:
undefined
,
useLocalStorage
:
false
,
localStorageExpirationTime
:
7
*
24
*
60
*
60
*
1000
,
dynamicLoad
:
false
,
sendMissing
:
false
,
sendMissingTo
:
'
fallback
'
,
// current | all
sendType
:
'
POST
'
,
interpolationPrefix
:
'
__
'
,
interpolationSuffix
:
'
__
'
,
reusePrefix
:
'
$t(
'
,
reuseSuffix
:
'
)
'
,
pluralSuffix
:
'
_plural
'
,
pluralNotFound
:
[
'
plural_not_found
'
,
Math
.
random
()].
join
(
''
),
contextNotFound
:
[
'
context_not_found
'
,
Math
.
random
()].
join
(
''
),
escapeInterpolation
:
false
,
setJqueryExt
:
true
,
defaultValueFromContent
:
true
,
useDataAttrOptions
:
false
,
cookieExpirationTime
:
undefined
,
useCookie
:
true
,
cookieName
:
'
i18next
'
,
cookieDomain
:
undefined
,
postProcess
:
undefined
,
parseMissingKey
:
undefined
,
shortcutFunction
:
'
sprintf
'
// or: defaultValue
};
function
_extend
(
target
,
source
)
{
if
(
!
source
||
typeof
source
===
'
function
'
)
{
return
target
;
}
for
(
var
attr
in
source
)
{
target
[
attr
]
=
source
[
attr
];
}
return
target
;
}
function
_each
(
object
,
callback
,
args
)
{
var
name
,
i
=
0
,
length
=
object
.
length
,
isObj
=
length
===
undefined
||
typeof
object
===
"
function
"
;
if
(
args
)
{
if
(
isObj
)
{
for
(
name
in
object
)
{
if
(
callback
.
apply
(
object
[
name
],
args
)
===
false
)
{
break
;
}
}
}
else
{
for
(
;
i
<
length
;
)
{
if
(
callback
.
apply
(
object
[
i
++
],
args
)
===
false
)
{
break
;
}
}
}
// A special, fast, case for the most common use of each
}
else
{
if
(
isObj
)
{
for
(
name
in
object
)
{
if
(
callback
.
call
(
object
[
name
],
name
,
object
[
name
])
===
false
)
{
break
;
}
}
}
else
{
for
(
;
i
<
length
;
)
{
if
(
callback
.
call
(
object
[
i
],
i
,
object
[
i
++
])
===
false
)
{
break
;
}
}
}
}
return
object
;
}
var
_entityMap
=
{
"
&
"
:
"
&
"
,
"
<
"
:
"
<
"
,
"
>
"
:
"
>
"
,
'
"
'
:
'
"
'
,
"
'
"
:
'
'
'
,
"
/
"
:
'
/
'
};
function
_escape
(
data
)
{
if
(
typeof
data
===
'
string
'
)
{
return
data
.
replace
(
/
[
&<>"'
\/]
/g
,
function
(
s
)
{
return
_entityMap
[
s
];
});
}
else
{
return
data
;
}
}
function
_ajax
(
options
)
{
// v0.5.0 of https://github.com/goloroden/http.js
var
getXhr
=
function
(
callback
)
{
// Use the native XHR object if the browser supports it.
if
(
window
.
XMLHttpRequest
)
{
return
callback
(
null
,
new
XMLHttpRequest
());
}
else
if
(
window
.
ActiveXObject
)
{
// In Internet Explorer check for ActiveX versions of the XHR object.
try
{
return
callback
(
null
,
new
ActiveXObject
(
"
Msxml2.XMLHTTP
"
));
}
catch
(
e
)
{
return
callback
(
null
,
new
ActiveXObject
(
"
Microsoft.XMLHTTP
"
));
}
}
// If no XHR support was found, throw an error.
return
callback
(
new
Error
());
};
var
encodeUsingUrlEncoding
=
function
(
data
)
{
if
(
typeof
data
===
'
string
'
)
{
return
data
;
}
var
result
=
[];
for
(
var
dataItem
in
data
)
{
if
(
data
.
hasOwnProperty
(
dataItem
))
{
result
.
push
(
encodeURIComponent
(
dataItem
)
+
'
=
'
+
encodeURIComponent
(
data
[
dataItem
]));
}
}
return
result
.
join
(
'
&
'
);
};
var
utf8
=
function
(
text
)
{
text
=
text
.
replace
(
/
\r\n
/g
,
'
\n
'
);
var
result
=
''
;
for
(
var
i
=
0
;
i
<
text
.
length
;
i
++
)
{
var
c
=
text
.
charCodeAt
(
i
);
if
(
c
<
128
)
{
result
+=
String
.
fromCharCode
(
c
);
}
else
if
((
c
>
127
)
&&
(
c
<
2048
))
{
result
+=
String
.
fromCharCode
((
c
>>
6
)
|
192
);
result
+=
String
.
fromCharCode
((
c
&
63
)
|
128
);
}
else
{
result
+=
String
.
fromCharCode
((
c
>>
12
)
|
224
);
result
+=
String
.
fromCharCode
(((
c
>>
6
)
&
63
)
|
128
);
result
+=
String
.
fromCharCode
((
c
&
63
)
|
128
);
}
}
return
result
;
};
var
base64
=
function
(
text
)
{
var
keyStr
=
'
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
'
;
text
=
utf8
(
text
);
var
result
=
''
,
chr1
,
chr2
,
chr3
,
enc1
,
enc2
,
enc3
,
enc4
,
i
=
0
;
do
{
chr1
=
text
.
charCodeAt
(
i
++
);
chr2
=
text
.
charCodeAt
(
i
++
);
chr3
=
text
.
charCodeAt
(
i
++
);
enc1
=
chr1
>>
2
;
enc2
=
((
chr1
&
3
)
<<
4
)
|
(
chr2
>>
4
);
enc3
=
((
chr2
&
15
)
<<
2
)
|
(
chr3
>>
6
);
enc4
=
chr3
&
63
;
if
(
isNaN
(
chr2
))
{
enc3
=
enc4
=
64
;
}
else
if
(
isNaN
(
chr3
))
{
enc4
=
64
;
}
result
+=
keyStr
.
charAt
(
enc1
)
+
keyStr
.
charAt
(
enc2
)
+
keyStr
.
charAt
(
enc3
)
+
keyStr
.
charAt
(
enc4
);
chr1
=
chr2
=
chr3
=
''
;
enc1
=
enc2
=
enc3
=
enc4
=
''
;
}
while
(
i
<
text
.
length
);
return
result
;
};
var
mergeHeaders
=
function
()
{
// Use the first header object as base.
var
result
=
arguments
[
0
];
// Iterate through the remaining header objects and add them.
for
(
var
i
=
1
;
i
<
arguments
.
length
;
i
++
)
{
var
currentHeaders
=
arguments
[
i
];
for
(
var
header
in
currentHeaders
)
{
if
(
currentHeaders
.
hasOwnProperty
(
header
))
{
result
[
header
]
=
currentHeaders
[
header
];
}
}
}
// Return the merged headers.
return
result
;
};
var
ajax
=
function
(
method
,
url
,
options
,
callback
)
{
// Adjust parameters.
if
(
typeof
options
===
'
function
'
)
{
callback
=
options
;
options
=
{};
}
// Set default parameter values.
options
.
cache
=
options
.
cache
||
false
;
options
.
data
=
options
.
data
||
{};
options
.
headers
=
options
.
headers
||
{};
options
.
jsonp
=
options
.
jsonp
||
false
;
options
.
async
=
options
.
async
===
undefined
?
true
:
options
.
async
;
// Merge the various header objects.
var
headers
=
mergeHeaders
({
'
accept
'
:
'
*/*
'
,
'
content-type
'
:
'
application/x-www-form-urlencoded;charset=UTF-8
'
},
ajax
.
headers
,
options
.
headers
);
// Encode the data according to the content-type.
var
payload
;
if
(
headers
[
'
content-type
'
]
===
'
application/json
'
)
{
payload
=
JSON
.
stringify
(
options
.
data
);
}
else
{
payload
=
encodeUsingUrlEncoding
(
options
.
data
);
}
// Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
// if neccessary.
if
(
method
===
'
GET
'
)
{
// Setup the query string.
var
queryString
=
[];
if
(
payload
)
{
queryString
.
push
(
payload
);
payload
=
null
;
}
// Handle caching.
if
(
!
options
.
cache
)
{
queryString
.
push
(
'
_=
'
+
(
new
Date
()).
getTime
());
}
// If neccessary prepare the query string for a JSONP call.
if
(
options
.
jsonp
)
{
queryString
.
push
(
'
callback=
'
+
options
.
jsonp
);
queryString
.
push
(
'
jsonp=
'
+
options
.
jsonp
);
}
// Merge the query string and attach it to the url.
queryString
=
queryString
.
join
(
'
&
'
);
if
(
queryString
.
length
>
1
)
{
if
(
url
.
indexOf
(
'
?
'
)
>
-
1
)
{
url
+=
'
&
'
+
queryString
;
}
else
{
url
+=
'
?
'
+
queryString
;
}
}
// Make a JSONP call if neccessary.
if
(
options
.
jsonp
)
{
var
head
=
document
.
getElementsByTagName
(
'
head
'
)[
0
];
var
script
=
document
.
createElement
(
'
script
'
);
script
.
type
=
'
text/javascript
'
;
script
.
src
=
url
;
head
.
appendChild
(
script
);
return
;
}
}
// Since we got here, it is no JSONP request, so make a normal XHR request.
getXhr
(
function
(
err
,
xhr
)
{
if
(
err
)
return
callback
(
err
);
// Open the request.
xhr
.
open
(
method
,
url
,
options
.
async
);
// Set the request headers.
for
(
var
header
in
headers
)
{
if
(
headers
.
hasOwnProperty
(
header
))
{
xhr
.
setRequestHeader
(
header
,
headers
[
header
]);
}
}
// Handle the request events.
xhr
.
onreadystatechange
=
function
()
{
if
(
xhr
.
readyState
===
4
)
{
var
data
=
xhr
.
responseText
||
''
;
// If no callback is given, return.
if
(
!
callback
)
{
return
;
}
// Return an object that provides access to the data as text and JSON.
callback
(
xhr
.
status
,
{
text
:
function
()
{
return
data
;
},
json
:
function
()
{
return
JSON
.
parse
(
data
);
}
});
}
};
// Actually send the XHR request.
xhr
.
send
(
payload
);
});
};
// Define the external interface.
var
http
=
{
authBasic
:
function
(
username
,
password
)
{
ajax
.
headers
[
'
Authorization
'
]
=
'
Basic
'
+
base64
(
username
+
'
:
'
+
password
);
},
connect
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
CONNECT
'
,
url
,
options
,
callback
);
},
del
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
DELETE
'
,
url
,
options
,
callback
);
},
get
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
GET
'
,
url
,
options
,
callback
);
},
head
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
HEAD
'
,
url
,
options
,
callback
);
},
headers
:
function
(
headers
)
{
ajax
.
headers
=
headers
||
{};
},
isAllowed
:
function
(
url
,
verb
,
callback
)
{
this
.
options
(
url
,
function
(
status
,
data
)
{
callback
(
data
.
text
().
indexOf
(
verb
)
!==
-
1
);
});
},
options
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
OPTIONS
'
,
url
,
options
,
callback
);
},
patch
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
PATCH
'
,
url
,
options
,
callback
);
},
post
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
POST
'
,
url
,
options
,
callback
);
},
put
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
PUT
'
,
url
,
options
,
callback
);
},
trace
:
function
(
url
,
options
,
callback
)
{
return
ajax
(
'
TRACE
'
,
url
,
options
,
callback
);
}
};
var
methode
=
options
.
type
?
options
.
type
.
toLowerCase
()
:
'
get
'
;
http
[
methode
](
options
.
url
,
options
,
function
(
status
,
data
)
{
if
(
status
===
200
)
{
options
.
success
(
data
.
json
(),
status
,
null
);
}
else
{
options
.
error
(
data
.
text
(),
status
,
null
);
}
});
}
var
_cookie
=
{
create
:
function
(
name
,
value
,
minutes
,
domain
)
{
var
expires
;
if
(
minutes
)
{
var
date
=
new
Date
();
date
.
setTime
(
date
.
getTime
()
+
(
minutes
*
60
*
1000
));
expires
=
"
; expires=
"
+
date
.
toGMTString
();
}
else
expires
=
""
;
domain
=
(
domain
)?
"
domain=
"
+
domain
+
"
;
"
:
""
;
document
.
cookie
=
name
+
"
=
"
+
value
+
expires
+
"
;
"
+
domain
+
"
path=/
"
;
},
read
:
function
(
name
)
{
var
nameEQ
=
name
+
"
=
"
;
var
ca
=
document
.
cookie
.
split
(
'
;
'
);
for
(
var
i
=
0
;
i
<
ca
.
length
;
i
++
)
{
var
c
=
ca
[
i
];
while
(
c
.
charAt
(
0
)
==
'
'
)
c
=
c
.
substring
(
1
,
c
.
length
);
if
(
c
.
indexOf
(
nameEQ
)
===
0
)
return
c
.
substring
(
nameEQ
.
length
,
c
.
length
);
}
return
null
;
},
remove
:
function
(
name
)
{
this
.
create
(
name
,
""
,
-
1
);
}
};
var
cookie_noop
=
{
create
:
function
(
name
,
value
,
minutes
,
domain
)
{},
read
:
function
(
name
)
{
return
null
;
},
remove
:
function
(
name
)
{}
};
// move dependent functions to a container so that
// they can be overriden easier in no jquery environment (node.js)
var
f
=
{
extend
:
$
?
$
.
extend
:
_extend
,
each
:
$
?
$
.
each
:
_each
,
ajax
:
$
?
$
.
ajax
:
_ajax
,
cookie
:
typeof
document
!==
'
undefined
'
?
_cookie
:
cookie_noop
,
detectLanguage
:
detectLanguage
,
escape
:
_escape
,
log
:
function
(
str
)
{
if
(
o
.
debug
&&
typeof
console
!==
"
undefined
"
)
console
.
log
(
str
);
},
toLanguages
:
function
(
lng
)
{
var
languages
=
[];
if
(
typeof
lng
===
'
string
'
&&
lng
.
indexOf
(
'
-
'
)
>
-
1
)
{
var
parts
=
lng
.
split
(
'
-
'
);
lng
=
o
.
lowerCaseLng
?
parts
[
0
].
toLowerCase
()
+
'
-
'
+
parts
[
1
].
toLowerCase
()
:
parts
[
0
].
toLowerCase
()
+
'
-
'
+
parts
[
1
].
toUpperCase
();
if
(
o
.
load
!==
'
unspecific
'
)
languages
.
push
(
lng
);
if
(
o
.
load
!==
'
current
'
)
languages
.
push
(
parts
[
0
]);
}
else
{
languages
.
push
(
lng
);
}
if
(
languages
.
indexOf
(
o
.
fallbackLng
)
===
-
1
&&
o
.
fallbackLng
)
languages
.
push
(
o
.
fallbackLng
);
return
languages
;
},
regexEscape
:
function
(
str
)
{
return
str
.
replace
(
/
[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]
/g
,
"
\\
$&
"
);
}
};
function
init
(
options
,
cb
)
{
if
(
typeof
options
===
'
function
'
)
{
cb
=
options
;
options
=
{};
}
options
=
options
||
{};
// override defaults with passed in options
f
.
extend
(
o
,
options
);
delete
o
.
fixLng
;
/* passed in each time */
// create namespace object if namespace is passed in as string
if
(
typeof
o
.
ns
==
'
string
'
)
{
o
.
ns
=
{
namespaces
:
[
o
.
ns
],
defaultNs
:
o
.
ns
};
}
// fallback namespaces
if
(
typeof
o
.
fallbackNS
==
'
string
'
)
{
o
.
fallbackNS
=
[
o
.
fallbackNS
];
}
// escape prefix/suffix
o
.
interpolationPrefixEscaped
=
f
.
regexEscape
(
o
.
interpolationPrefix
);
o
.
interpolationSuffixEscaped
=
f
.
regexEscape
(
o
.
interpolationSuffix
);
if
(
!
o
.
lng
)
o
.
lng
=
f
.
detectLanguage
();
if
(
o
.
lng
)
{
// set cookie with lng set (as detectLanguage will set cookie on need)
if
(
o
.
useCookie
)
f
.
cookie
.
create
(
o
.
cookieName
,
o
.
lng
,
o
.
cookieExpirationTime
,
o
.
cookieDomain
);
}
else
{
o
.
lng
=
o
.
fallbackLng
;
if
(
o
.
useCookie
)
f
.
cookie
.
remove
(
o
.
cookieName
);
}
languages
=
f
.
toLanguages
(
o
.
lng
);
currentLng
=
languages
[
0
];
f
.
log
(
'
currentLng set to:
'
+
currentLng
);
var
lngTranslate
=
translate
;
if
(
options
.
fixLng
)
{
lngTranslate
=
function
(
key
,
options
)
{
options
=
options
||
{};
options
.
lng
=
options
.
lng
||
lngTranslate
.
lng
;
return
translate
(
key
,
options
);
};
lngTranslate
.
lng
=
currentLng
;
}
pluralExtensions
.
setCurrentLng
(
currentLng
);
// add JQuery extensions
if
(
$
&&
o
.
setJqueryExt
)
addJqueryFunct
();
// jQuery deferred
var
deferred
;
if
(
$
&&
$
.
Deferred
)
{
deferred
=
$
.
Deferred
();
}
// return immidiatly if res are passed in
if
(
o
.
resStore
)
{
resStore
=
o
.
resStore
;
initialized
=
true
;
if
(
cb
)
cb
(
lngTranslate
);
if
(
deferred
)
deferred
.
resolve
(
lngTranslate
);
if
(
deferred
)
return
deferred
.
promise
();
return
;
}
// languages to load
var
lngsToLoad
=
f
.
toLanguages
(
o
.
lng
);
if
(
typeof
o
.
preload
===
'
string
'
)
o
.
preload
=
[
o
.
preload
];
for
(
var
i
=
0
,
l
=
o
.
preload
.
length
;
i
<
l
;
i
++
)
{
var
pres
=
f
.
toLanguages
(
o
.
preload
[
i
]);
for
(
var
y
=
0
,
len
=
pres
.
length
;
y
<
len
;
y
++
)
{
if
(
lngsToLoad
.
indexOf
(
pres
[
y
])
<
0
)
{
lngsToLoad
.
push
(
pres
[
y
]);
}
}
}
// else load them
i18n
.
sync
.
load
(
lngsToLoad
,
o
,
function
(
err
,
store
)
{
resStore
=
store
;
initialized
=
true
;
if
(
cb
)
cb
(
lngTranslate
);
if
(
deferred
)
deferred
.
resolve
(
lngTranslate
);
});
if
(
deferred
)
return
deferred
.
promise
();
}
function
preload
(
lngs
,
cb
)
{
if
(
typeof
lngs
===
'
string
'
)
lngs
=
[
lngs
];
for
(
var
i
=
0
,
l
=
lngs
.
length
;
i
<
l
;
i
++
)
{
if
(
o
.
preload
.
indexOf
(
lngs
[
i
])
<
0
)
{
o
.
preload
.
push
(
lngs
[
i
]);
}
}
return
init
(
cb
);
}
function
addResourceBundle
(
lng
,
ns
,
resources
)
{
if
(
typeof
ns
!==
'
string
'
)
{
resources
=
ns
;
ns
=
o
.
ns
.
defaultNs
;
}
else
if
(
o
.
ns
.
namespaces
.
indexOf
(
ns
)
<
0
)
{
o
.
ns
.
namespaces
.
push
(
ns
);
}
resStore
[
lng
]
=
resStore
[
lng
]
||
{};
resStore
[
lng
][
ns
]
=
resStore
[
lng
][
ns
]
||
{};
f
.
extend
(
resStore
[
lng
][
ns
],
resources
);
}
function
setDefaultNamespace
(
ns
)
{
o
.
ns
.
defaultNs
=
ns
;
}
function
loadNamespace
(
namespace
,
cb
)
{
loadNamespaces
([
namespace
],
cb
);
}
function
loadNamespaces
(
namespaces
,
cb
)
{
var
opts
=
{
dynamicLoad
:
o
.
dynamicLoad
,
resGetPath
:
o
.
resGetPath
,
getAsync
:
o
.
getAsync
,
customLoad
:
o
.
customLoad
,
ns
:
{
namespaces
:
namespaces
,
defaultNs
:
''
}
/* new namespaces to load */
};
// languages to load
var
lngsToLoad
=
f
.
toLanguages
(
o
.
lng
);
if
(
typeof
o
.
preload
===
'
string
'
)
o
.
preload
=
[
o
.
preload
];
for
(
var
i
=
0
,
l
=
o
.
preload
.
length
;
i
<
l
;
i
++
)
{
var
pres
=
f
.
toLanguages
(
o
.
preload
[
i
]);
for
(
var
y
=
0
,
len
=
pres
.
length
;
y
<
len
;
y
++
)
{
if
(
lngsToLoad
.
indexOf
(
pres
[
y
])
<
0
)
{
lngsToLoad
.
push
(
pres
[
y
]);
}
}
}
// check if we have to load
var
lngNeedLoad
=
[];
for
(
var
a
=
0
,
lenA
=
lngsToLoad
.
length
;
a
<
lenA
;
a
++
)
{
var
needLoad
=
false
;
var
resSet
=
resStore
[
lngsToLoad
[
a
]];
if
(
resSet
)
{
for
(
var
b
=
0
,
lenB
=
namespaces
.
length
;
b
<
lenB
;
b
++
)
{
if
(
!
resSet
[
namespaces
[
b
]])
needLoad
=
true
;
}
}
else
{
needLoad
=
true
;
}
if
(
needLoad
)
lngNeedLoad
.
push
(
lngsToLoad
[
a
]);
}
if
(
lngNeedLoad
.
length
)
{
i18n
.
sync
.
_fetch
(
lngNeedLoad
,
opts
,
function
(
err
,
store
)
{
var
todo
=
namespaces
.
length
*
lngNeedLoad
.
length
;
// load each file individual
f
.
each
(
namespaces
,
function
(
nsIndex
,
nsValue
)
{
// append namespace to namespace array
if
(
o
.
ns
.
namespaces
.
indexOf
(
nsValue
)
<
0
)
{
o
.
ns
.
namespaces
.
push
(
nsValue
);
}
f
.
each
(
lngNeedLoad
,
function
(
lngIndex
,
lngValue
)
{
resStore
[
lngValue
]
=
resStore
[
lngValue
]
||
{};
resStore
[
lngValue
][
nsValue
]
=
store
[
lngValue
][
nsValue
];
todo
--
;
// wait for all done befor callback
if
(
todo
===
0
&&
cb
)
{
if
(
o
.
useLocalStorage
)
i18n
.
sync
.
_storeLocal
(
resStore
);
cb
();
}
});
});
});
}
else
{
if
(
cb
)
cb
();
}
}
function
setLng
(
lng
,
options
,
cb
)
{
if
(
typeof
options
===
'
function
'
)
{
cb
=
options
;
options
=
{};
}
options
.
lng
=
lng
;
return
init
(
options
,
cb
);
}
function
lng
()
{
return
currentLng
;
}
function
addJqueryFunct
()
{
// $.t shortcut
$
.
t
=
$
.
t
||
translate
;
function
parse
(
ele
,
key
,
options
)
{
if
(
key
.
length
===
0
)
return
;
var
attr
=
'
text
'
;
if
(
key
.
indexOf
(
'
[
'
)
===
0
)
{
var
parts
=
key
.
split
(
'
]
'
);
key
=
parts
[
1
];
attr
=
parts
[
0
].
substr
(
1
,
parts
[
0
].
length
-
1
);
}
if
(
key
.
indexOf
(
'
;
'
)
===
key
.
length
-
1
)
{
key
=
key
.
substr
(
0
,
key
.
length
-
2
);
}
var
optionsToUse
;
if
(
attr
===
'
html
'
)
{
optionsToUse
=
o
.
defaultValueFromContent
?
$
.
extend
({
defaultValue
:
ele
.
html
()
},
options
)
:
options
;
ele
.
html
(
$
.
t
(
key
,
optionsToUse
));
}
else
if
(
attr
===
'
text
'
)
{
optionsToUse
=
o
.
defaultValueFromContent
?
$
.
extend
({
defaultValue
:
ele
.
text
()
},
options
)
:
options
;
ele
.
text
(
$
.
t
(
key
,
optionsToUse
));
}
else
{
optionsToUse
=
o
.
defaultValueFromContent
?
$
.
extend
({
defaultValue
:
ele
.
attr
(
attr
)
},
options
)
:
options
;
ele
.
attr
(
attr
,
$
.
t
(
key
,
optionsToUse
));
}
}
function
localize
(
ele
,
options
)
{
var
key
=
ele
.
attr
(
o
.
selectorAttr
);
if
(
!
key
&&
typeof
key
!==
'
undefined
'
&&
key
!==
false
)
key
=
ele
.
text
()
||
ele
.
val
();
if
(
!
key
)
return
;
var
target
=
ele
,
targetSelector
=
ele
.
data
(
"
i18n-target
"
);
if
(
targetSelector
)
{
target
=
ele
.
find
(
targetSelector
)
||
ele
;
}
if
(
!
options
&&
o
.
useDataAttrOptions
===
true
)
{
options
=
ele
.
data
(
"
i18n-options
"
);
}
options
=
options
||
{};
if
(
key
.
indexOf
(
'
;
'
)
>=
0
)
{
var
keys
=
key
.
split
(
'
;
'
);
$
.
each
(
keys
,
function
(
m
,
k
)
{
if
(
k
!==
''
)
parse
(
target
,
k
,
options
);
});
}
else
{
parse
(
target
,
key
,
options
);
}
if
(
o
.
useDataAttrOptions
===
true
)
ele
.
data
(
"
i18n-options
"
,
options
);
}
// fn
$
.
fn
.
i18n
=
function
(
options
)
{
return
this
.
each
(
function
()
{
// localize element itself
localize
(
$
(
this
),
options
);
// localize childs
var
elements
=
$
(
this
).
find
(
'
[
'
+
o
.
selectorAttr
+
'
]
'
);
elements
.
each
(
function
()
{
localize
(
$
(
this
),
options
);
});
});
};
}
function
applyReplacement
(
str
,
replacementHash
,
nestedKey
,
options
)
{
if
(
!
str
)
return
str
;
options
=
options
||
replacementHash
;
// first call uses replacement hash combined with options
if
(
str
.
indexOf
(
options
.
interpolationPrefix
||
o
.
interpolationPrefix
)
<
0
)
return
str
;
var
prefix
=
options
.
interpolationPrefix
?
f
.
regexEscape
(
options
.
interpolationPrefix
)
:
o
.
interpolationPrefixEscaped
,
suffix
=
options
.
interpolationSuffix
?
f
.
regexEscape
(
options
.
interpolationSuffix
)
:
o
.
interpolationSuffixEscaped
,
unEscapingSuffix
=
'
HTML
'
+
suffix
;
f
.
each
(
replacementHash
,
function
(
key
,
value
)
{
var
nextKey
=
nestedKey
?
nestedKey
+
o
.
keyseparator
+
key
:
key
;
if
(
typeof
value
===
'
object
'
&&
value
!==
null
)
{
str
=
applyReplacement
(
str
,
value
,
nextKey
,
options
);
}
else
{
if
(
options
.
escapeInterpolation
||
o
.
escapeInterpolation
)
{
str
=
str
.
replace
(
new
RegExp
([
prefix
,
nextKey
,
unEscapingSuffix
].
join
(
''
),
'
g
'
),
value
);
str
=
str
.
replace
(
new
RegExp
([
prefix
,
nextKey
,
suffix
].
join
(
''
),
'
g
'
),
f
.
escape
(
value
));
}
else
{
str
=
str
.
replace
(
new
RegExp
([
prefix
,
nextKey
,
suffix
].
join
(
''
),
'
g
'
),
value
);
}
// str = options.escapeInterpolation;
}
});
return
str
;
}
// append it to functions
f
.
applyReplacement
=
applyReplacement
;
function
applyReuse
(
translated
,
options
)
{
var
comma
=
'
,
'
;
var
options_open
=
'
{
'
;
var
options_close
=
'
}
'
;
var
opts
=
f
.
extend
({},
options
);
delete
opts
.
postProcess
;
while
(
translated
.
indexOf
(
o
.
reusePrefix
)
!=
-
1
)
{
replacementCounter
++
;
if
(
replacementCounter
>
o
.
maxRecursion
)
{
break
;
}
// safety net for too much recursion
var
index_of_opening
=
translated
.
lastIndexOf
(
o
.
reusePrefix
);
var
index_of_end_of_closing
=
translated
.
indexOf
(
o
.
reuseSuffix
,
index_of_opening
)
+
o
.
reuseSuffix
.
length
;
var
token
=
translated
.
substring
(
index_of_opening
,
index_of_end_of_closing
);
var
token_without_symbols
=
token
.
replace
(
o
.
reusePrefix
,
''
).
replace
(
o
.
reuseSuffix
,
''
);
if
(
token_without_symbols
.
indexOf
(
comma
)
!=
-
1
)
{
var
index_of_token_end_of_closing
=
token_without_symbols
.
indexOf
(
comma
);
if
(
token_without_symbols
.
indexOf
(
options_open
,
index_of_token_end_of_closing
)
!=
-
1
&&
token_without_symbols
.
indexOf
(
options_close
,
index_of_token_end_of_closing
)
!=
-
1
)
{
var
index_of_opts_opening
=
token_without_symbols
.
indexOf
(
options_open
,
index_of_token_end_of_closing
);
var
index_of_opts_end_of_closing
=
token_without_symbols
.
indexOf
(
options_close
,
index_of_opts_opening
)
+
options_close
.
length
;
try
{
opts
=
f
.
extend
(
opts
,
JSON
.
parse
(
token_without_symbols
.
substring
(
index_of_opts_opening
,
index_of_opts_end_of_closing
)));
token_without_symbols
=
token_without_symbols
.
substring
(
0
,
index_of_token_end_of_closing
);
}
catch
(
e
)
{
}
}
}
var
translated_token
=
_translate
(
token_without_symbols
,
opts
);
translated
=
translated
.
replace
(
token
,
translated_token
);
}
return
translated
;
}
function
hasContext
(
options
)
{
return
(
options
.
context
&&
typeof
options
.
context
==
'
string
'
);
}
function
needsPlural
(
options
)
{
return
(
options
.
count
!==
undefined
&&
typeof
options
.
count
!=
'
string
'
&&
options
.
count
!==
1
);
}
function
exists
(
key
,
options
)
{
options
=
options
||
{};
var
notFound
=
_getDefaultValue
(
key
,
options
)
,
found
=
_find
(
key
,
options
);
return
found
!==
undefined
||
found
===
notFound
;
}
function
translate
(
key
,
options
)
{
if
(
!
initialized
)
{
f
.
log
(
'
i18next not finished initialization. you might have called t function before loading resources finished.
'
)
return
options
.
defaultValue
||
''
;
};
replacementCounter
=
0
;
return
_translate
.
apply
(
null
,
arguments
);
}
function
_getDefaultValue
(
key
,
options
)
{
return
(
options
.
defaultValue
!==
undefined
)
?
options
.
defaultValue
:
key
;
}
function
_injectSprintfProcessor
()
{
var
values
=
[];
// mh: build array from second argument onwards
for
(
var
i
=
1
;
i
<
arguments
.
length
;
i
++
)
{
values
.
push
(
arguments
[
i
]);
}
return
{
postProcess
:
'
sprintf
'
,
sprintf
:
values
};
}
function
_translate
(
potentialKeys
,
options
)
{
if
(
typeof
options
==
'
string
'
)
{
if
(
o
.
shortcutFunction
===
'
sprintf
'
)
{
// mh: gettext like sprintf syntax found, automatically create sprintf processor
options
=
_injectSprintfProcessor
.
apply
(
null
,
arguments
);
}
else
if
(
o
.
shortcutFunction
===
'
defaultValue
'
)
{
options
=
{
defaultValue
:
options
}
}
}
else
{
options
=
options
||
{};
}
if
(
typeof
potentialKeys
==
'
string
'
)
{
potentialKeys
=
[
potentialKeys
];
}
var
key
=
null
;
for
(
var
i
=
0
;
i
<
potentialKeys
.
length
;
i
++
)
{
key
=
potentialKeys
[
i
];
if
(
exists
(
key
))
{
break
;
}
}
var
notFound
=
_getDefaultValue
(
key
,
options
)
,
found
=
_find
(
key
,
options
)
,
lngs
=
options
.
lng
?
f
.
toLanguages
(
options
.
lng
)
:
languages
,
ns
=
options
.
ns
||
o
.
ns
.
defaultNs
,
parts
;
// split ns and key
if
(
key
.
indexOf
(
o
.
nsseparator
)
>
-
1
)
{
parts
=
key
.
split
(
o
.
nsseparator
);
ns
=
parts
[
0
];
key
=
parts
[
1
];
}
if
(
found
===
undefined
&&
o
.
sendMissing
)
{
if
(
options
.
lng
)
{
sync
.
postMissing
(
lngs
[
0
],
ns
,
key
,
notFound
,
lngs
);
}
else
{
sync
.
postMissing
(
o
.
lng
,
ns
,
key
,
notFound
,
lngs
);
}
}
var
postProcessor
=
options
.
postProcess
||
o
.
postProcess
;
if
(
found
!==
undefined
&&
postProcessor
)
{
if
(
postProcessors
[
postProcessor
])
{
found
=
postProcessors
[
postProcessor
](
found
,
key
,
options
);
}
}
// process notFound if function exists
var
splitNotFound
=
notFound
;
if
(
notFound
.
indexOf
(
o
.
nsseparator
)
>
-
1
)
{
parts
=
notFound
.
split
(
o
.
nsseparator
);
splitNotFound
=
parts
[
1
];
}
if
(
splitNotFound
===
key
&&
o
.
parseMissingKey
)
{
notFound
=
o
.
parseMissingKey
(
notFound
);
}
if
(
found
===
undefined
)
{
notFound
=
applyReplacement
(
notFound
,
options
);
notFound
=
applyReuse
(
notFound
,
options
);
if
(
postProcessor
&&
postProcessors
[
postProcessor
])
{
var
val
=
_getDefaultValue
(
key
,
options
);
found
=
postProcessors
[
postProcessor
](
val
,
key
,
options
);
}
}
return
(
found
!==
undefined
)
?
found
:
notFound
;
}
function
_find
(
key
,
options
){
options
=
options
||
{};
var
optionWithoutCount
,
translated
,
notFound
=
_getDefaultValue
(
key
,
options
)
,
lngs
=
languages
;
if
(
!
resStore
)
{
return
notFound
;
}
// no resStore to translate from
if
(
options
.
lng
)
{
lngs
=
f
.
toLanguages
(
options
.
lng
);
if
(
!
resStore
[
lngs
[
0
]])
{
var
oldAsync
=
o
.
getAsync
;
o
.
getAsync
=
false
;
i18n
.
sync
.
load
(
lngs
,
o
,
function
(
err
,
store
)
{
f
.
extend
(
resStore
,
store
);
o
.
getAsync
=
oldAsync
;
});
}
}
var
ns
=
options
.
ns
||
o
.
ns
.
defaultNs
;
if
(
key
.
indexOf
(
o
.
nsseparator
)
>
-
1
)
{
var
parts
=
key
.
split
(
o
.
nsseparator
);
ns
=
parts
[
0
];
key
=
parts
[
1
];
}
if
(
hasContext
(
options
))
{
optionWithoutCount
=
f
.
extend
({},
options
);
delete
optionWithoutCount
.
context
;
optionWithoutCount
.
defaultValue
=
o
.
contextNotFound
;
var
contextKey
=
ns
+
o
.
nsseparator
+
key
+
'
_
'
+
options
.
context
;
translated
=
translate
(
contextKey
,
optionWithoutCount
);
if
(
translated
!=
o
.
contextNotFound
)
{
return
applyReplacement
(
translated
,
{
context
:
options
.
context
});
// apply replacement for context only
}
// else continue translation with original/nonContext key
}
if
(
needsPlural
(
options
))
{
optionWithoutCount
=
f
.
extend
({},
options
);
delete
optionWithoutCount
.
count
;
optionWithoutCount
.
defaultValue
=
o
.
pluralNotFound
;
var
pluralKey
=
ns
+
o
.
nsseparator
+
key
+
o
.
pluralSuffix
;
var
pluralExtension
=
pluralExtensions
.
get
(
lngs
[
0
],
options
.
count
);
if
(
pluralExtension
>=
0
)
{
pluralKey
=
pluralKey
+
'
_
'
+
pluralExtension
;
}
else
if
(
pluralExtension
===
1
)
{
pluralKey
=
ns
+
o
.
nsseparator
+
key
;
// singular
}
translated
=
translate
(
pluralKey
,
optionWithoutCount
);
if
(
translated
!=
o
.
pluralNotFound
)
{
return
applyReplacement
(
translated
,
{
count
:
options
.
count
,
interpolationPrefix
:
options
.
interpolationPrefix
,
interpolationSuffix
:
options
.
interpolationSuffix
});
// apply replacement for count only
}
// else continue translation with original/singular key
}
var
found
;
var
keys
=
key
.
split
(
o
.
keyseparator
);
for
(
var
i
=
0
,
len
=
lngs
.
length
;
i
<
len
;
i
++
)
{
if
(
found
!==
undefined
)
break
;
var
l
=
lngs
[
i
];
var
x
=
0
;
var
value
=
resStore
[
l
]
&&
resStore
[
l
][
ns
];
while
(
keys
[
x
])
{
value
=
value
&&
value
[
keys
[
x
]];
x
++
;
}
if
(
value
!==
undefined
)
{
if
(
typeof
value
===
'
string
'
)
{
value
=
applyReplacement
(
value
,
options
);
value
=
applyReuse
(
value
,
options
);
}
else
if
(
Object
.
prototype
.
toString
.
apply
(
value
)
===
'
[object Array]
'
&&
!
o
.
returnObjectTrees
&&
!
options
.
returnObjectTrees
)
{
value
=
value
.
join
(
'
\n
'
);
value
=
applyReplacement
(
value
,
options
);
value
=
applyReuse
(
value
,
options
);
}
else
if
(
value
===
null
&&
o
.
fallbackOnNull
===
true
)
{
value
=
undefined
;
}
else
if
(
value
!==
null
)
{
if
(
!
o
.
returnObjectTrees
&&
!
options
.
returnObjectTrees
)
{
value
=
'
key
\'
'
+
ns
+
'
:
'
+
key
+
'
(
'
+
l
+
'
)
\'
'
+
'
returned a object instead of string.
'
;
f
.
log
(
value
);
}
else
if
(
typeof
value
!==
'
number
'
)
{
var
copy
=
{};
// apply child translation on a copy
f
.
each
(
value
,
function
(
m
)
{
copy
[
m
]
=
_translate
(
ns
+
o
.
nsseparator
+
key
+
o
.
keyseparator
+
m
,
options
);
});
value
=
copy
;
}
}
found
=
value
;
}
}
if
(
found
===
undefined
&&
!
options
.
isFallbackLookup
&&
(
o
.
fallbackToDefaultNS
===
true
||
(
o
.
fallbackNS
&&
o
.
fallbackNS
.
length
>
0
)))
{
// set flag for fallback lookup - avoid recursion
options
.
isFallbackLookup
=
true
;
if
(
o
.
fallbackNS
.
length
)
{
for
(
var
y
=
0
,
lenY
=
o
.
fallbackNS
.
length
;
y
<
lenY
;
y
++
)
{
found
=
_find
(
o
.
fallbackNS
[
y
]
+
o
.
nsseparator
+
key
,
options
);
if
(
found
)
{
/* compare value without namespace */
var
foundValue
=
found
.
indexOf
(
o
.
nsseparator
)
>
-
1
?
found
.
split
(
o
.
nsseparator
)[
1
]
:
found
,
notFoundValue
=
notFound
.
indexOf
(
o
.
nsseparator
)
>
-
1
?
notFound
.
split
(
o
.
nsseparator
)[
1
]
:
notFound
;
if
(
foundValue
!==
notFoundValue
)
break
;
}
}
}
else
{
found
=
_find
(
key
,
options
);
// fallback to default NS
}
}
return
found
;
}
function
detectLanguage
()
{
var
detectedLng
;
// get from qs
var
qsParm
=
[];
if
(
typeof
window
!==
'
undefined
'
)
{
(
function
()
{
var
query
=
window
.
location
.
search
.
substring
(
1
);
var
parms
=
query
.
split
(
'
&
'
);
for
(
var
i
=
0
;
i
<
parms
.
length
;
i
++
)
{
var
pos
=
parms
[
i
].
indexOf
(
'
=
'
);
if
(
pos
>
0
)
{
var
key
=
parms
[
i
].
substring
(
0
,
pos
);
var
val
=
parms
[
i
].
substring
(
pos
+
1
);
qsParm
[
key
]
=
val
;
}
}
})();
if
(
qsParm
[
o
.
detectLngQS
])
{
detectedLng
=
qsParm
[
o
.
detectLngQS
];
}
}
// get from cookie
if
(
!
detectedLng
&&
typeof
document
!==
'
undefined
'
&&
o
.
useCookie
)
{
var
c
=
f
.
cookie
.
read
(
o
.
cookieName
);
if
(
c
)
detectedLng
=
c
;
}
// get from navigator
if
(
!
detectedLng
&&
typeof
navigator
!==
'
undefined
'
)
{
detectedLng
=
(
navigator
.
language
)
?
navigator
.
language
:
navigator
.
userLanguage
;
}
return
detectedLng
;
}
var
sync
=
{
load
:
function
(
lngs
,
options
,
cb
)
{
if
(
options
.
useLocalStorage
)
{
sync
.
_loadLocal
(
lngs
,
options
,
function
(
err
,
store
)
{
var
missingLngs
=
[];
for
(
var
i
=
0
,
len
=
lngs
.
length
;
i
<
len
;
i
++
)
{
if
(
!
store
[
lngs
[
i
]])
missingLngs
.
push
(
lngs
[
i
]);
}
if
(
missingLngs
.
length
>
0
)
{
sync
.
_fetch
(
missingLngs
,
options
,
function
(
err
,
fetched
)
{
f
.
extend
(
store
,
fetched
);
sync
.
_storeLocal
(
fetched
);
cb
(
null
,
store
);
});
}
else
{
cb
(
null
,
store
);
}
});
}
else
{
sync
.
_fetch
(
lngs
,
options
,
function
(
err
,
store
){
cb
(
null
,
store
);
});
}
},
_loadLocal
:
function
(
lngs
,
options
,
cb
)
{
var
store
=
{}
,
nowMS
=
new
Date
().
getTime
();
if
(
window
.
localStorage
)
{
var
todo
=
lngs
.
length
;
f
.
each
(
lngs
,
function
(
key
,
lng
)
{
var
local
=
window
.
localStorage
.
getItem
(
'
res_
'
+
lng
);
if
(
local
)
{
local
=
JSON
.
parse
(
local
);
if
(
local
.
i18nStamp
&&
local
.
i18nStamp
+
options
.
localStorageExpirationTime
>
nowMS
)
{
store
[
lng
]
=
local
;
}
}
todo
--
;
// wait for all done befor callback
if
(
todo
===
0
)
cb
(
null
,
store
);
});
}
},
_storeLocal
:
function
(
store
)
{
if
(
window
.
localStorage
)
{
for
(
var
m
in
store
)
{
store
[
m
].
i18nStamp
=
new
Date
().
getTime
();
window
.
localStorage
.
setItem
(
'
res_
'
+
m
,
JSON
.
stringify
(
store
[
m
]));
}
}
return
;
},
_fetch
:
function
(
lngs
,
options
,
cb
)
{
var
ns
=
options
.
ns
,
store
=
{};
if
(
!
options
.
dynamicLoad
)
{
var
todo
=
ns
.
namespaces
.
length
*
lngs
.
length
,
errors
;
// load each file individual
f
.
each
(
ns
.
namespaces
,
function
(
nsIndex
,
nsValue
)
{
f
.
each
(
lngs
,
function
(
lngIndex
,
lngValue
)
{
// Call this once our translation has returned.
var
loadComplete
=
function
(
err
,
data
)
{
if
(
err
)
{
errors
=
errors
||
[];
errors
.
push
(
err
);
}
store
[
lngValue
]
=
store
[
lngValue
]
||
{};
store
[
lngValue
][
nsValue
]
=
data
;
todo
--
;
// wait for all done befor callback
if
(
todo
===
0
)
cb
(
errors
,
store
);
};
if
(
typeof
options
.
customLoad
==
'
function
'
){
// Use the specified custom callback.
options
.
customLoad
(
lngValue
,
nsValue
,
options
,
loadComplete
);
}
else
{
//~ // Use our inbuilt sync.
sync
.
_fetchOne
(
lngValue
,
nsValue
,
options
,
loadComplete
);
}
});
});
}
else
{
// Call this once our translation has returned.
var
loadComplete
=
function
(
err
,
data
)
{
cb
(
null
,
data
);
};
if
(
typeof
options
.
customLoad
==
'
function
'
){
// Use the specified custom callback.
options
.
customLoad
(
lngs
,
ns
.
namespaces
,
options
,
loadComplete
);
}
else
{
var
url
=
applyReplacement
(
options
.
resGetPath
,
{
lng
:
lngs
.
join
(
'
+
'
),
ns
:
ns
.
namespaces
.
join
(
'
+
'
)
});
// load all needed stuff once
f
.
ajax
({
url
:
url
,
success
:
function
(
data
,
status
,
xhr
)
{
f
.
log
(
'
loaded:
'
+
url
);
loadComplete
(
null
,
data
);
},
error
:
function
(
xhr
,
status
,
error
)
{
f
.
log
(
'
failed loading:
'
+
url
);
loadComplete
(
'
failed loading resource.json error:
'
+
error
);
},
dataType
:
"
json
"
,
async
:
options
.
getAsync
});
}
}
},
_fetchOne
:
function
(
lng
,
ns
,
options
,
done
)
{
var
url
=
applyReplacement
(
options
.
resGetPath
,
{
lng
:
lng
,
ns
:
ns
});
f
.
ajax
({
url
:
url
,
success
:
function
(
data
,
status
,
xhr
)
{
f
.
log
(
'
loaded:
'
+
url
);
done
(
null
,
data
);
},
error
:
function
(
xhr
,
status
,
error
)
{
f
.
log
(
'
failed loading:
'
+
url
);
done
(
error
,
{});
},
dataType
:
"
json
"
,
async
:
options
.
getAsync
});
},
postMissing
:
function
(
lng
,
ns
,
key
,
defaultValue
,
lngs
)
{
var
payload
=
{};
payload
[
key
]
=
defaultValue
;
var
urls
=
[];
if
(
o
.
sendMissingTo
===
'
fallback
'
&&
o
.
fallbackLng
!==
false
)
{
urls
.
push
({
lng
:
o
.
fallbackLng
,
url
:
applyReplacement
(
o
.
resPostPath
,
{
lng
:
o
.
fallbackLng
,
ns
:
ns
})});
}
else
if
(
o
.
sendMissingTo
===
'
current
'
||
(
o
.
sendMissingTo
===
'
fallback
'
&&
o
.
fallbackLng
===
false
)
)
{
urls
.
push
({
lng
:
lng
,
url
:
applyReplacement
(
o
.
resPostPath
,
{
lng
:
lng
,
ns
:
ns
})});
}
else
if
(
o
.
sendMissingTo
===
'
all
'
)
{
for
(
var
i
=
0
,
l
=
lngs
.
length
;
i
<
l
;
i
++
)
{
urls
.
push
({
lng
:
lngs
[
i
],
url
:
applyReplacement
(
o
.
resPostPath
,
{
lng
:
lngs
[
i
],
ns
:
ns
})});
}
}
for
(
var
y
=
0
,
len
=
urls
.
length
;
y
<
len
;
y
++
)
{
var
item
=
urls
[
y
];
f
.
ajax
({
url
:
item
.
url
,
type
:
o
.
sendType
,
data
:
payload
,
success
:
function
(
data
,
status
,
xhr
)
{
f
.
log
(
'
posted missing key
\'
'
+
key
+
'
\'
to:
'
+
item
.
url
);
// add key to resStore
var
keys
=
key
.
split
(
'
.
'
);
var
x
=
0
;
var
value
=
resStore
[
item
.
lng
][
ns
];
while
(
keys
[
x
])
{
if
(
x
===
keys
.
length
-
1
)
{
value
=
value
[
keys
[
x
]]
=
defaultValue
;
}
else
{
value
=
value
[
keys
[
x
]]
=
value
[
keys
[
x
]]
||
{};
}
x
++
;
}
},
error
:
function
(
xhr
,
status
,
error
)
{
f
.
log
(
'
failed posting missing key
\'
'
+
key
+
'
\'
to:
'
+
item
.
url
);
},
dataType
:
"
json
"
,
async
:
o
.
postAsync
});
}
}
};
// definition http://translate.sourceforge.net/wiki/l10n/pluralforms
var
pluralExtensions
=
{
rules
:
{
"
ach
"
:
{
"
name
"
:
"
Acholi
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
af
"
:
{
"
name
"
:
"
Afrikaans
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ak
"
:
{
"
name
"
:
"
Akan
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
am
"
:
{
"
name
"
:
"
Amharic
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
an
"
:
{
"
name
"
:
"
Aragonese
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ar
"
:
{
"
name
"
:
"
Arabic
"
,
"
numbers
"
:
[
0
,
1
,
2
,
3
,
11
,
100
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
===
0
?
0
:
n
==
1
?
1
:
n
==
2
?
2
:
n
%
100
>=
3
&&
n
%
100
<=
10
?
3
:
n
%
100
>=
11
?
4
:
5
);
}
},
"
arn
"
:
{
"
name
"
:
"
Mapudungun
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
ast
"
:
{
"
name
"
:
"
Asturian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ay
"
:
{
"
name
"
:
"
Aymar
\
u00e1
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
az
"
:
{
"
name
"
:
"
Azerbaijani
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
be
"
:
{
"
name
"
:
"
Belarusian
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
bg
"
:
{
"
name
"
:
"
Bulgarian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
bn
"
:
{
"
name
"
:
"
Bengali
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
bo
"
:
{
"
name
"
:
"
Tibetan
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
br
"
:
{
"
name
"
:
"
Breton
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
bs
"
:
{
"
name
"
:
"
Bosnian
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
ca
"
:
{
"
name
"
:
"
Catalan
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
cgg
"
:
{
"
name
"
:
"
Chiga
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
cs
"
:
{
"
name
"
:
"
Czech
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
((
n
==
1
)
?
0
:
(
n
>=
2
&&
n
<=
4
)
?
1
:
2
);
}
},
"
csb
"
:
{
"
name
"
:
"
Kashubian
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
==
1
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
cy
"
:
{
"
name
"
:
"
Welsh
"
,
"
numbers
"
:
[
1
,
2
,
3
,
8
],
"
plurals
"
:
function
(
n
)
{
return
Number
((
n
==
1
)
?
0
:
(
n
==
2
)
?
1
:
(
n
!=
8
&&
n
!=
11
)
?
2
:
3
);
}
},
"
da
"
:
{
"
name
"
:
"
Danish
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
de
"
:
{
"
name
"
:
"
German
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
dz
"
:
{
"
name
"
:
"
Dzongkha
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
el
"
:
{
"
name
"
:
"
Greek
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
en
"
:
{
"
name
"
:
"
English
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
eo
"
:
{
"
name
"
:
"
Esperanto
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
es
"
:
{
"
name
"
:
"
Spanish
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
es_ar
"
:
{
"
name
"
:
"
Argentinean Spanish
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
et
"
:
{
"
name
"
:
"
Estonian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
eu
"
:
{
"
name
"
:
"
Basque
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
fa
"
:
{
"
name
"
:
"
Persian
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
fi
"
:
{
"
name
"
:
"
Finnish
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
fil
"
:
{
"
name
"
:
"
Filipino
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
fo
"
:
{
"
name
"
:
"
Faroese
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
fr
"
:
{
"
name
"
:
"
French
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
fur
"
:
{
"
name
"
:
"
Friulian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
fy
"
:
{
"
name
"
:
"
Frisian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ga
"
:
{
"
name
"
:
"
Irish
"
,
"
numbers
"
:
[
1
,
2
,
3
,
7
,
11
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
==
1
?
0
:
n
==
2
?
1
:
n
<
7
?
2
:
n
<
11
?
3
:
4
)
;}
},
"
gd
"
:
{
"
name
"
:
"
Scottish Gaelic
"
,
"
numbers
"
:
[
1
,
2
,
3
,
20
],
"
plurals
"
:
function
(
n
)
{
return
Number
((
n
==
1
||
n
==
11
)
?
0
:
(
n
==
2
||
n
==
12
)
?
1
:
(
n
>
2
&&
n
<
20
)
?
2
:
3
);
}
},
"
gl
"
:
{
"
name
"
:
"
Galician
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
gu
"
:
{
"
name
"
:
"
Gujarati
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
gun
"
:
{
"
name
"
:
"
Gun
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
ha
"
:
{
"
name
"
:
"
Hausa
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
he
"
:
{
"
name
"
:
"
Hebrew
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
hi
"
:
{
"
name
"
:
"
Hindi
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
hr
"
:
{
"
name
"
:
"
Croatian
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
hu
"
:
{
"
name
"
:
"
Hungarian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
hy
"
:
{
"
name
"
:
"
Armenian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ia
"
:
{
"
name
"
:
"
Interlingua
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
id
"
:
{
"
name
"
:
"
Indonesian
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
is
"
:
{
"
name
"
:
"
Icelandic
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
!=
1
||
n
%
100
==
11
);
}
},
"
it
"
:
{
"
name
"
:
"
Italian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ja
"
:
{
"
name
"
:
"
Japanese
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
jbo
"
:
{
"
name
"
:
"
Lojban
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
jv
"
:
{
"
name
"
:
"
Javanese
"
,
"
numbers
"
:
[
0
,
1
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!==
0
);
}
},
"
ka
"
:
{
"
name
"
:
"
Georgian
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
kk
"
:
{
"
name
"
:
"
Kazakh
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
km
"
:
{
"
name
"
:
"
Khmer
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
kn
"
:
{
"
name
"
:
"
Kannada
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ko
"
:
{
"
name
"
:
"
Korean
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
ku
"
:
{
"
name
"
:
"
Kurdish
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
kw
"
:
{
"
name
"
:
"
Cornish
"
,
"
numbers
"
:
[
1
,
2
,
3
,
4
],
"
plurals
"
:
function
(
n
)
{
return
Number
((
n
==
1
)
?
0
:
(
n
==
2
)
?
1
:
(
n
==
3
)
?
2
:
3
);
}
},
"
ky
"
:
{
"
name
"
:
"
Kyrgyz
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
lb
"
:
{
"
name
"
:
"
Letzeburgesch
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ln
"
:
{
"
name
"
:
"
Lingala
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
lo
"
:
{
"
name
"
:
"
Lao
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
lt
"
:
{
"
name
"
:
"
Lithuanian
"
,
"
numbers
"
:
[
1
,
2
,
10
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
%
10
>=
2
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
lv
"
:
{
"
name
"
:
"
Latvian
"
,
"
numbers
"
:
[
0
,
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
!==
0
?
1
:
2
);
}
},
"
mai
"
:
{
"
name
"
:
"
Maithili
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
mfe
"
:
{
"
name
"
:
"
Mauritian Creole
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
mg
"
:
{
"
name
"
:
"
Malagasy
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
mi
"
:
{
"
name
"
:
"
Maori
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
mk
"
:
{
"
name
"
:
"
Macedonian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
==
1
||
n
%
10
==
1
?
0
:
1
);
}
},
"
ml
"
:
{
"
name
"
:
"
Malayalam
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
mn
"
:
{
"
name
"
:
"
Mongolian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
mnk
"
:
{
"
name
"
:
"
Mandinka
"
,
"
numbers
"
:
[
0
,
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
0
?
0
:
n
==
1
?
1
:
2
);
}
},
"
mr
"
:
{
"
name
"
:
"
Marathi
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ms
"
:
{
"
name
"
:
"
Malay
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
mt
"
:
{
"
name
"
:
"
Maltese
"
,
"
numbers
"
:
[
1
,
2
,
11
,
20
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
==
1
?
0
:
n
===
0
||
(
n
%
100
>
1
&&
n
%
100
<
11
)
?
1
:
(
n
%
100
>
10
&&
n
%
100
<
20
)
?
2
:
3
);
}
},
"
nah
"
:
{
"
name
"
:
"
Nahuatl
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
nap
"
:
{
"
name
"
:
"
Neapolitan
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
nb
"
:
{
"
name
"
:
"
Norwegian Bokmal
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ne
"
:
{
"
name
"
:
"
Nepali
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
nl
"
:
{
"
name
"
:
"
Dutch
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
nn
"
:
{
"
name
"
:
"
Norwegian Nynorsk
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
no
"
:
{
"
name
"
:
"
Norwegian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
nso
"
:
{
"
name
"
:
"
Northern Sotho
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
oc
"
:
{
"
name
"
:
"
Occitan
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
or
"
:
{
"
name
"
:
"
Oriya
"
,
"
numbers
"
:
[
2
,
1
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
pa
"
:
{
"
name
"
:
"
Punjabi
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
pap
"
:
{
"
name
"
:
"
Papiamento
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
pl
"
:
{
"
name
"
:
"
Polish
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
==
1
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
pms
"
:
{
"
name
"
:
"
Piemontese
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ps
"
:
{
"
name
"
:
"
Pashto
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
pt
"
:
{
"
name
"
:
"
Portuguese
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
pt_br
"
:
{
"
name
"
:
"
Brazilian Portuguese
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
rm
"
:
{
"
name
"
:
"
Romansh
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ro
"
:
{
"
name
"
:
"
Romanian
"
,
"
numbers
"
:
[
1
,
2
,
20
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
==
1
?
0
:
(
n
===
0
||
(
n
%
100
>
0
&&
n
%
100
<
20
))
?
1
:
2
);
}
},
"
ru
"
:
{
"
name
"
:
"
Russian
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
sah
"
:
{
"
name
"
:
"
Yakut
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
sco
"
:
{
"
name
"
:
"
Scots
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
se
"
:
{
"
name
"
:
"
Northern Sami
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
si
"
:
{
"
name
"
:
"
Sinhala
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
sk
"
:
{
"
name
"
:
"
Slovak
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
((
n
==
1
)
?
0
:
(
n
>=
2
&&
n
<=
4
)
?
1
:
2
);
}
},
"
sl
"
:
{
"
name
"
:
"
Slovenian
"
,
"
numbers
"
:
[
5
,
1
,
2
,
3
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
100
==
1
?
1
:
n
%
100
==
2
?
2
:
n
%
100
==
3
||
n
%
100
==
4
?
3
:
0
);
}
},
"
so
"
:
{
"
name
"
:
"
Somali
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
son
"
:
{
"
name
"
:
"
Songhay
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
sq
"
:
{
"
name
"
:
"
Albanian
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
sr
"
:
{
"
name
"
:
"
Serbian
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
su
"
:
{
"
name
"
:
"
Sundanese
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
sv
"
:
{
"
name
"
:
"
Swedish
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
sw
"
:
{
"
name
"
:
"
Swahili
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
ta
"
:
{
"
name
"
:
"
Tamil
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
te
"
:
{
"
name
"
:
"
Telugu
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
tg
"
:
{
"
name
"
:
"
Tajik
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
th
"
:
{
"
name
"
:
"
Thai
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
ti
"
:
{
"
name
"
:
"
Tigrinya
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
tk
"
:
{
"
name
"
:
"
Turkmen
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
tr
"
:
{
"
name
"
:
"
Turkish
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
tt
"
:
{
"
name
"
:
"
Tatar
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
ug
"
:
{
"
name
"
:
"
Uyghur
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
uk
"
:
{
"
name
"
:
"
Ukrainian
"
,
"
numbers
"
:
[
1
,
2
,
5
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
%
10
==
1
&&
n
%
100
!=
11
?
0
:
n
%
10
>=
2
&&
n
%
10
<=
4
&&
(
n
%
100
<
10
||
n
%
100
>=
20
)
?
1
:
2
);
}
},
"
ur
"
:
{
"
name
"
:
"
Urdu
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
uz
"
:
{
"
name
"
:
"
Uzbek
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
vi
"
:
{
"
name
"
:
"
Vietnamese
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
wa
"
:
{
"
name
"
:
"
Walloon
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
>
1
);
}
},
"
wo
"
:
{
"
name
"
:
"
Wolof
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
},
"
yo
"
:
{
"
name
"
:
"
Yoruba
"
,
"
numbers
"
:
[
1
,
2
],
"
plurals
"
:
function
(
n
)
{
return
Number
(
n
!=
1
);
}
},
"
zh
"
:
{
"
name
"
:
"
Chinese
"
,
"
numbers
"
:
[
1
],
"
plurals
"
:
function
(
n
)
{
return
0
;
}
}
},
// for demonstration only sl and ar is added but you can add your own pluralExtensions
addRule
:
function
(
lng
,
obj
)
{
pluralExtensions
.
rules
[
lng
]
=
obj
;
},
setCurrentLng
:
function
(
lng
)
{
if
(
!
pluralExtensions
.
currentRule
||
pluralExtensions
.
currentRule
.
lng
!==
lng
)
{
var
parts
=
lng
.
split
(
'
-
'
);
pluralExtensions
.
currentRule
=
{
lng
:
lng
,
rule
:
pluralExtensions
.
rules
[
parts
[
0
]]
};
}
},
get
:
function
(
lng
,
count
)
{
var
parts
=
lng
.
split
(
'
-
'
);
function
getResult
(
l
,
c
)
{
var
ext
;
if
(
pluralExtensions
.
currentRule
&&
pluralExtensions
.
currentRule
.
lng
===
lng
)
{
ext
=
pluralExtensions
.
currentRule
.
rule
;
}
else
{
ext
=
pluralExtensions
.
rules
[
l
];
}
if
(
ext
)
{
var
i
=
ext
.
plurals
(
c
);
var
number
=
ext
.
numbers
[
i
];
if
(
ext
.
numbers
.
length
===
2
&&
ext
.
numbers
[
0
]
===
1
)
{
if
(
number
===
2
)
{
number
=
-
1
;
// regular plural
}
else
if
(
number
===
1
)
{
number
=
1
;
// singular
}
}
//console.log(count + '-' + number);
return
number
;
}
else
{
return
c
===
1
?
'
1
'
:
'
-1
'
;
}
}
return
getResult
(
parts
[
0
],
count
);
}
};
var
postProcessors
=
{};
var
addPostProcessor
=
function
(
name
,
fc
)
{
postProcessors
[
name
]
=
fc
;
};
// sprintf support
var
sprintf
=
(
function
()
{
function
get_type
(
variable
)
{
return
Object
.
prototype
.
toString
.
call
(
variable
).
slice
(
8
,
-
1
).
toLowerCase
();
}
function
str_repeat
(
input
,
multiplier
)
{
for
(
var
output
=
[];
multiplier
>
0
;
output
[
--
multiplier
]
=
input
)
{
/* do nothing */
}
return
output
.
join
(
''
);
}
var
str_format
=
function
()
{
if
(
!
str_format
.
cache
.
hasOwnProperty
(
arguments
[
0
]))
{
str_format
.
cache
[
arguments
[
0
]]
=
str_format
.
parse
(
arguments
[
0
]);
}
return
str_format
.
format
.
call
(
null
,
str_format
.
cache
[
arguments
[
0
]],
arguments
);
};
str_format
.
format
=
function
(
parse_tree
,
argv
)
{
var
cursor
=
1
,
tree_length
=
parse_tree
.
length
,
node_type
=
''
,
arg
,
output
=
[],
i
,
k
,
match
,
pad
,
pad_character
,
pad_length
;
for
(
i
=
0
;
i
<
tree_length
;
i
++
)
{
node_type
=
get_type
(
parse_tree
[
i
]);
if
(
node_type
===
'
string
'
)
{
output
.
push
(
parse_tree
[
i
]);
}
else
if
(
node_type
===
'
array
'
)
{
match
=
parse_tree
[
i
];
// convenience purposes only
if
(
match
[
2
])
{
// keyword argument
arg
=
argv
[
cursor
];
for
(
k
=
0
;
k
<
match
[
2
].
length
;
k
++
)
{
if
(
!
arg
.
hasOwnProperty
(
match
[
2
][
k
]))
{
throw
(
sprintf
(
'
[sprintf] property "%s" does not exist
'
,
match
[
2
][
k
]));
}
arg
=
arg
[
match
[
2
][
k
]];
}
}
else
if
(
match
[
1
])
{
// positional argument (explicit)
arg
=
argv
[
match
[
1
]];
}
else
{
// positional argument (implicit)
arg
=
argv
[
cursor
++
];
}
if
(
/
[^
s
]
/
.
test
(
match
[
8
])
&&
(
get_type
(
arg
)
!=
'
number
'
))
{
throw
(
sprintf
(
'
[sprintf] expecting number but found %s
'
,
get_type
(
arg
)));
}
switch
(
match
[
8
])
{
case
'
b
'
:
arg
=
arg
.
toString
(
2
);
break
;
case
'
c
'
:
arg
=
String
.
fromCharCode
(
arg
);
break
;
case
'
d
'
:
arg
=
parseInt
(
arg
,
10
);
break
;
case
'
e
'
:
arg
=
match
[
7
]
?
arg
.
toExponential
(
match
[
7
])
:
arg
.
toExponential
();
break
;
case
'
f
'
:
arg
=
match
[
7
]
?
parseFloat
(
arg
).
toFixed
(
match
[
7
])
:
parseFloat
(
arg
);
break
;
case
'
o
'
:
arg
=
arg
.
toString
(
8
);
break
;
case
'
s
'
:
arg
=
((
arg
=
String
(
arg
))
&&
match
[
7
]
?
arg
.
substring
(
0
,
match
[
7
])
:
arg
);
break
;
case
'
u
'
:
arg
=
Math
.
abs
(
arg
);
break
;
case
'
x
'
:
arg
=
arg
.
toString
(
16
);
break
;
case
'
X
'
:
arg
=
arg
.
toString
(
16
).
toUpperCase
();
break
;
}
arg
=
(
/
[
def
]
/
.
test
(
match
[
8
])
&&
match
[
3
]
&&
arg
>=
0
?
'
+
'
+
arg
:
arg
);
pad_character
=
match
[
4
]
?
match
[
4
]
==
'
0
'
?
'
0
'
:
match
[
4
].
charAt
(
1
)
:
'
'
;
pad_length
=
match
[
6
]
-
String
(
arg
).
length
;
pad
=
match
[
6
]
?
str_repeat
(
pad_character
,
pad_length
)
:
''
;
output
.
push
(
match
[
5
]
?
arg
+
pad
:
pad
+
arg
);
}
}
return
output
.
join
(
''
);
};
str_format
.
cache
=
{};
str_format
.
parse
=
function
(
fmt
)
{
var
_fmt
=
fmt
,
match
=
[],
parse_tree
=
[],
arg_names
=
0
;
while
(
_fmt
)
{
if
((
match
=
/^
[^\x
25
]
+/
.
exec
(
_fmt
))
!==
null
)
{
parse_tree
.
push
(
match
[
0
]);
}
else
if
((
match
=
/^
\x
25
{2}
/
.
exec
(
_fmt
))
!==
null
)
{
parse_tree
.
push
(
'
%
'
);
}
else
if
((
match
=
/^
\x
25
(?:([
1-9
]\d
*
)\$
|
\(([^\)]
+
)\))?(\+)?(
0|'
[^
$
])?(
-
)?(\d
+
)?(?:\.(\d
+
))?([
b-fosuxX
])
/
.
exec
(
_fmt
))
!==
null
)
{
if
(
match
[
2
])
{
arg_names
|=
1
;
var
field_list
=
[],
replacement_field
=
match
[
2
],
field_match
=
[];
if
((
field_match
=
/^
([
a-z_
][
a-z_
\d]
*
)
/i
.
exec
(
replacement_field
))
!==
null
)
{
field_list
.
push
(
field_match
[
1
]);
while
((
replacement_field
=
replacement_field
.
substring
(
field_match
[
0
].
length
))
!==
''
)
{
if
((
field_match
=
/^
\.([
a-z_
][
a-z_
\d]
*
)
/i
.
exec
(
replacement_field
))
!==
null
)
{
field_list
.
push
(
field_match
[
1
]);
}
else
if
((
field_match
=
/^
\[(\d
+
)\]
/
.
exec
(
replacement_field
))
!==
null
)
{
field_list
.
push
(
field_match
[
1
]);
}
else
{
throw
(
'
[sprintf] huh?
'
);
}
}
}
else
{
throw
(
'
[sprintf] huh?
'
);
}
match
[
2
]
=
field_list
;
}
else
{
arg_names
|=
2
;
}
if
(
arg_names
===
3
)
{
throw
(
'
[sprintf] mixing positional and named placeholders is not (yet) supported
'
);
}
parse_tree
.
push
(
match
);
}
else
{
throw
(
'
[sprintf] huh?
'
);
}
_fmt
=
_fmt
.
substring
(
match
[
0
].
length
);
}
return
parse_tree
;
};
return
str_format
;
})();
var
vsprintf
=
function
(
fmt
,
argv
)
{
argv
.
unshift
(
fmt
);
return
sprintf
.
apply
(
null
,
argv
);
};
addPostProcessor
(
"
sprintf
"
,
function
(
val
,
key
,
opts
)
{
if
(
!
opts
.
sprintf
)
return
val
;
if
(
Object
.
prototype
.
toString
.
apply
(
opts
.
sprintf
)
===
'
[object Array]
'
)
{
return
vsprintf
(
val
,
opts
.
sprintf
);
}
else
if
(
typeof
opts
.
sprintf
===
'
object
'
)
{
return
sprintf
(
val
,
opts
.
sprintf
);
}
return
val
;
});
// public api interface
i18n
.
init
=
init
;
i18n
.
setLng
=
setLng
;
i18n
.
preload
=
preload
;
i18n
.
addResourceBundle
=
addResourceBundle
;
i18n
.
loadNamespace
=
loadNamespace
;
i18n
.
loadNamespaces
=
loadNamespaces
;
i18n
.
setDefaultNamespace
=
setDefaultNamespace
;
i18n
.
t
=
translate
;
i18n
.
translate
=
translate
;
i18n
.
exists
=
exists
;
i18n
.
detectLanguage
=
f
.
detectLanguage
;
i18n
.
pluralExtensions
=
pluralExtensions
;
i18n
.
sync
=
sync
;
i18n
.
functions
=
f
;
i18n
.
lng
=
lng
;
i18n
.
addPostProcessor
=
addPostProcessor
;
i18n
.
options
=
o
;
})();
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment