UNPKG

there

Version:
173 lines (139 loc) 7.35 kB
_ = require "underscore" # Use this as a mixin for classes that have words to name / translate. # See [lin](http://astrolet.github.com/lin/)'s `Ensemble` # as an example of what the `@words` object must be like. # For a more varied example of words / localization data, see # [there](http://astrolet.github.com/there/)'s # [care](http://astrolet.github.com/there/annotations/care.html). # Suppose an attribute of "name" - quite usual, often the only (necessary). # Thus expect that `@words.expect is ['name']`, while the actual words data # must be in conformance with each `@words.data[id][attribute][language]` # set to a `["Hermes Name", "Modern Name"]` array. # **`Hermes Name`** is the Hellenistic Astrology (System of Hermes) name. # If the **`Hermes Name`** is `true`, rather than a string, it means that # the **`Modern Name`** is equivalent to the original Greek word. # If it's `null` (with other languages), then it hasn't been revised, # meaning it's possibly sub-optimal for Hellenistic Astrology use. # A value of false means it's deemed unfit for Hellenistic Astrology. # In order to be `@translatable` a collection needs to have its initial data # set up. Look at [lin](http://astrolet.github.com/lin)'s # [Ensemble](http://astrolet.github.com/lin/annotations/ensemble.html) # - more pecifically how `@planets.the` and `@planets.attributes.use` # are expected in addition to `@words`. # There can be more than one initialization objects, but a single `@words` # data set for translation - basically the collection as a whole. # Example usage within the `constructor` / `initialize`: # _.extend @, polyglot.ensure # @translatable() is true module.exports = { ensure: translatable: (inits) -> # English words must be present (at least), but also many other things... # It's kind of pointless to check for it all. Perhaps a try / catch - as # another way to return `false`. Another idea: check if anything is to be # `push`ed and have that determine the return value. if @words? and not _.isEmpty inits # Expected instance variables will get defaults if not already set. @school ?= "h" @language ?= "en" # Will this work on the client-side? _.extend @, module.exports.methods # Initialize the translatable data. for init in inits # The same translatable attributes must be used across the collection. # This isn't immediately obvious, looking at a single init hash. for i in [0 .. @words.expect.length - 1] expected = @words.expect[i] # the translated key filledIn = @words.filler[i] # default, if no translation is present sequence = init.the[0].length + i init.attributes.use[expected] = sequence # If each row's expected item is not in `words.data[{key}][{expect}]` # add a default using `words.filler` data # from a corresponding array position. for row in init.the identifier = row[init.attributes.use[init.attributes.key]] substitute = row[init.attributes.use[filledIn]] # filled-in value @words.data[identifier] ?= {} unless @words.data[identifier][expected]? # console.log "not found: key '#{identifier}' for '#{expected}'" # console.log "using: #{substitute}" addition = en: [ false, substitute ] @words.data[identifier][expected] = addition # It's important to call `@translation` with sorted keys, # or else the `@words.data` order must match that of `init.the`. i = 0 for attributes in _.values @translation @language # and further... , @school , _.pluck(init.the, init.attributes.use[init.attributes.key]) # Add each attribute (without "key_id", which usually is the "id"). for attribute, word of attributes continue if attribute is "key_id" init.the[i].push word i++ true else false # The following are mixed in through an `if @translatable()` call / (check). methods: translation: ( language , school , keys = [] , select = @words.expect ) -> switch @school when "h" then position = 0 # hermes (hellenistic hindsight) when "m" then position = 1 # modern else throw "Unknown '#{@school}' position." if _.isEmpty keys then keys = _.keys @words.data else # Sorted according to `keys` order (intersection does), so `@words.data` # can be in any order. keys = _.intersection keys, _.keys @words.data # The `i` is immediately incremented for `out[i]` use. out = []; i = -1 for key in keys out[++i] = { "key_id": key } for word in select # The English language is used / mixed in for untranslated # or partially translated stuff. stuff = @words.data[key][word][@language] ? @words.data[key][word]['en'] if position is 0 value = stuff[position] if _.isString value then out[i][word] = value else switch value # The modern version is `true`, meaning it never deviated from # its Hellenistic roots. Or, in the case of `null` - # it's unknown if it will have to be translated. # Modern is assumed to be ok for the time being. # TODO: null doesn't seem to be picking the data (undefined)! when true || null then out[i][word] = stuff[1] # The modern version is unacceptable (what `false` means). # English default is always available (at least as modern). when false out[i][word] = @words.data[key][word]['en'][position] # The English fallback position 0, could be made more elegant. # Probably this whole translation should be refactored, # extracting a tranlateWord function to get in a language or # else call it again for English. unless _.isString out[i][word] out[i][word] = @words.data[key][word]['en'][1] # Assuming that every translated language has the modern vocabulary. else out[i][word] = stuff[position] out # Use an optional array of `select` attributes for partial translation. translate: (language = @language, school = @school, select) -> # The current implementation doesn't force-reload # the same language / school (pointless as the data is part of the code). if @language isnt language or @school isnt school @school = school @language = language for attributes in @translation @language , @school , @pluck('id') , select key = attributes.key_id delete attributes.key_id # Note that "get" is the default method for the `@words.data` key. @[@words.model || 'get'](key).set attributes @ # chainable }