64a87b1c67
- Translations are no longer fetched from the cloud. - Instead, they are extracted from the codebase and stored in i18n/zammad.pot. - Translations will be managed via a public Weblate instance soon. - The translated .po files are fed to the database as before. - It is now possible to change "translation" strings for en-us locally via the admin GUI. - It is no longer possible to submit local changes.
91 lines
No EOL
2.5 KiB
CoffeeScript
91 lines
No EOL
2.5 KiB
CoffeeScript
module.exports = class DetectTranslatableString
|
|
|
|
# coffeelint: disable=detect_translatable_string
|
|
rule:
|
|
name: 'detect_translatable_string'
|
|
level: 'ignore'
|
|
message: 'The following string looks like it should be marked as translatable via __(...)'
|
|
description: '''
|
|
'''
|
|
|
|
constructor: ->
|
|
@callTokens = []
|
|
|
|
tokens: ['STRING', 'CALL_START', 'CALL_END']
|
|
|
|
lintToken: (token, tokenApi) ->
|
|
[type, tokenValue] = token
|
|
|
|
if type in ['CALL_START', 'CALL_END']
|
|
@trackCall token, tokenApi
|
|
return
|
|
|
|
return false if @isInIgnoredMethod()
|
|
|
|
return @lintString(token, tokenApi)
|
|
|
|
lintString: (token, tokenApi) ->
|
|
[type, tokenValue] = token
|
|
|
|
# Remove quotes.
|
|
string = tokenValue[1..-2]
|
|
|
|
# Ignore strings with less than two words.
|
|
return false if string.split(' ').length < 2
|
|
|
|
# Ignore strings that are being used as exception; unlike Ruby exceptions, these should not reach the user.
|
|
return false if tokenApi.peek(-3)[1] == 'throw'
|
|
return false if tokenApi.peek(-2)[1] == 'throw'
|
|
return false if tokenApi.peek(-1)[1] == 'throw'
|
|
|
|
# Ignore strings that are being used for comparison
|
|
return false if tokenApi.peek(-1)[1] == '=='
|
|
|
|
# String interpolation is handled via concatenation, ignore such strings.
|
|
return false if tokenApi.peek(1)[1] == '+'
|
|
return false if tokenApi.peek(2)[1] == '+'
|
|
|
|
BLOCKLIST = [
|
|
# Only look at strings starting with upper case letters
|
|
/^[^A-Z]/,
|
|
# # Ignore strings starting with three upper case letters like SELECT, POST etc.
|
|
# /^[A-Z]{3}/,
|
|
]
|
|
|
|
return false if BLOCKLIST.some (entry) ->
|
|
#console.log([string, entry, string.match(entry), token, tokenApi.peek(-1), tokenApi.peek(1)])
|
|
string.match(entry)
|
|
|
|
# console.log(tokenApi.peek(-3))
|
|
# console.log(tokenApi.peek(-2))
|
|
# console.log(tokenApi.peek(-1))
|
|
# console.log(token)
|
|
|
|
return { context: "Found: #{token[1]}" }
|
|
|
|
ignoredMethods: {
|
|
'__': true,
|
|
'log': true,
|
|
'T': true,
|
|
'controllerBind': true,
|
|
'error': true, # App.Log.error
|
|
'set': true, # App.Config.set
|
|
'translateInline': true,
|
|
'translateContent': true,
|
|
'translatePlain': true,
|
|
}
|
|
|
|
isInIgnoredMethod: ->
|
|
#console.log(@callTokens)
|
|
for t in @callTokens
|
|
return true if t.isIgnoredMethod
|
|
return false
|
|
|
|
trackCall: (token, tokenApi) ->
|
|
if token[0] is 'CALL_START'
|
|
p = tokenApi.peek(-1)
|
|
token.isIgnoredMethod = p and @ignoredMethods[p[1]]
|
|
@callTokens.push(token)
|
|
else
|
|
@callTokens.pop()
|
|
return null |