translator
Version:
[ABANDONED] Translator for node and also for browser
376 lines (258 loc) • 9.37 kB
text/coffeescript
Cache = require 'cache-storage'
Storage = require 'cache-storage/lib/Storage/Storage'
Args = require 'normalize-arguments'
path = require './node/path'
pluralForms = require './pluralForms'
Loader = require './Loaders/Loader'
JsonLoader = require './Loaders/Json'
isBrowser = typeof window != 'undefined'
if !isBrowser
callsite = require 'callsite'
class Translator
loader: null
language: null
plurals: null
replacements: null
filters: null
data: null
cache: null
constructor: (pathOrLoader) ->
= {}
= {}
= []
= {}
if !pathOrLoader
throw new Error 'You have to set path to base directory or to config file or loader.'
if typeof pathOrLoader == 'string'
if pathOrLoader.charAt(0) == '.' && isBrowser
throw new Error 'Relative paths to dictionaries is not supported in browser.'
if pathOrLoader.charAt(0) == '.'
stack = callsite()
pathOrLoader = path.join(path.dirname(stack[1].getFileName()), pathOrLoader)
pathOrLoader = path.normalize(pathOrLoader)
config =
path: pathOrLoader
loader: 'Json'
if pathOrLoader.match(/\.json$/) != null
_config = require(pathOrLoader)
if typeof _config.path != 'undefined'
config.path = _config.path
if typeof _config.loader != 'undefined'
config.loader = _config.loader
if config.path.charAt(0) == '.'
config.path = path.join(path.dirname(pathOrLoader), config.path)
pathOrLoader = new(require './Loaders/' + config.loader)(config.path)
for language, data of pluralForms
expand: (main = null) ->
if main == null
main = if isBrowser then window else global
main._ = => .apply(@, arguments)
main._m = => .apply(@, arguments)
main._p = => .apply(@, arguments)
return main
setLoader: (loader) ->
if loader !instanceof Loader
throw new Error 'Loader must be an instance of translator/Loaders/Loader.'
= loader
invalidate: ->
= {}
setCacheStorage: (cacheStorage) ->
if !cacheStorage instanceof Storage
throw new Error 'Cache storage must be an instance of cache-storage/Storage/Storage.'
= new Cache cacheStorage, 'translator'
addPluralForm: (language, count, form) ->
[language] =
count: count
form: form
return @
addReplacement: (search, replacement) ->
[search] = replacement
return @
removeReplacement: (search) ->
if typeof [search] == 'undefined'
throw new Error 'Replacement ' + search + ' was not found.'
delete [search]
return @
addFilter: (fn) ->
.push(fn)
return @
applyFilters: (translation) ->
if Object.prototype.toString.call(translation) == '[object Array]'
for t, i in translation
translation[i] =
return translation
for filter in
translation = filter(translation)
return translation
loadCategory: (_path, name, language = ) ->
categoryName = _path + '/' + name
if typeof [categoryName] == 'undefined'
if == null
data = .load(_path, name, language)
data =
else
data = .load(language + ':' + categoryName)
if data == null
data = .load(_path, name, language)
data =
conds = {}
if typeof window == 'undefined' || (typeof window != 'undefined' && window.require.simq == true && typeof window.require.version != 'undefined' && parseInt(window.require.version.replace(/\./g, '')) >= 510)
_path = .getFileSystemPath(_path, name, language)
conds.files = [_path] if _path != null
.save(language + ':' + categoryName, data, conds)
else
file = .load(_path, name, language)
data =
[categoryName] = data
return [categoryName]
normalizeTranslations: (translations) ->
result = {}
for name, translation of translations
list = false
if (match = name.match(/^--\s(.*)/)) != null
name = match[1]
list = true
if typeof translation == 'string'
result[name] = [translation]
else if Object.prototype.toString.call(translation) == '[object Array]'
result[name] = []
for t in translation
if typeof t == 'object'
buf = []
for sub in t
if /^\#.*\#$/.test(sub) == false
buf.push sub
result[name].push buf
else
if /^\#.*\#$/.test(t) == false
if list == true && typeof t != 'object' then t = [t]
result[name].push t
return result
hasTranslation: (message, language = ) ->
return != null
findTranslation: (message, language = ) ->
info =
data =
return if typeof data[info.name] == 'undefined' then null else data[info.name]
translate: (message, count = null, args = {}) ->
params = Args(arguments, [Args.any, Args.number(null), Args.object({})])
message = params[0]
count = params[1]
args = params[2]
language =
found = false
if typeof message != 'string' then return message
if count != null then args.count = count
if (match = message.match(/^\:(.*)\:$/)) != null
message = match[1]
if (match = message.match(/^[a-z]+\|(.*)$/)) != null
message = match[1]
else
if (match = message.match(/^([a-z]+)\|(.*)$/)) != null
language = match[1]
message = match[2]
if language == null
throw new Error 'You have to set language.'
num = null
if (match = message.match(/(.+)\[(\d+)\]$/)) != null
message = match[1]
num = parseInt(match[2])
message =
translation =
found =
if num != null
if !
throw new Error 'Translation ' + message + ' is not a list.'
if typeof translation[num] == 'undefined'
throw new Error 'Item ' + num + ' was not found in ' + message + ' translation.'
translation = translation[num]
if translation != null
message =
message =
if found
message =
return message
translatePairs: (message, key, value, count = null, args = {}) ->
key = "#{message}.#{key}"
value = "#{message}.#{value}"
key =
value =
if Object.prototype.toString.call(key) != '[object Array]' || Object.prototype.toString.call(value) != '[object Array]'
throw new Error 'Translations are not arrays.'
if key.length != value.length
throw new Error 'Keys and values translations have not got the same length.'
result = {}
for k, i in key
result[k] = value[i]
return result
translateMap: (list, count = null, args = {}, base = null) ->
type = Object.prototype.toString.call(list)
if type not in ['[object Array]', '[object Object]']
throw new Error 'Translate map is only for arrays and objects.'
params = Args(arguments, [Args.oneOf([Args.array, Args.object]), Args.number(null), Args.object({}), Args.string(null)])
list = params[0]
count = params[1]
args = params[2]
base = params[3]
base = if base != null then base + '.' else ''
if type == '[object Array]'
for m, i in list
list[i] =
else
for k, m of list
list[k] =
return list
isList: (translation) ->
return Object.prototype.toString.call(translation[0]) == '[object Array]'
pluralize: (message, translation, count = null, language = ) ->
if count != null
if typeof translation[0] == 'string'
pluralForm = 'n=' + count + ';plural=+(' + [language].form + ');'
n = null
plural = null
eval(pluralForm)
message = if plural != null && typeof translation[plural] != 'undefined' then translation[plural] else translation[0]
else
result = []
result.push() for t in translation
message = result
else
if typeof translation[0] == 'string'
message = translation[0]
else
message = []
message.push(t[0]) for t in translation
return message
prepareTranslation: (message, args = {}) ->
if typeof message == 'string'
message =
else
result = []
for m in message
result.push()
message = result
return message
applyReplacements: (message, args = {}) ->
replacements =
for name, value of args
replacements[name] = value
for name, value of replacements
if value != false
pattern = new RegExp('%' + name + '%', 'g')
message = message.replace(pattern, value)
return message
getMessageInfo: (message) ->
num = message.lastIndexOf('.')
_path = message.substr(0, num)
name = message.substr(num + 1)
num = _path.lastIndexOf('.')
category = _path.substr(num + 1)
_path = _path.substr(0, num).replace(/\./g, '/')
result =
path: _path
category: category
name: name
return result
module.exports = Translator