Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom locale loader #35

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions lib/rules/no-html-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const {
findExistLocaleMessage,
getLocaleMessages,
extractJsonInfo,
generateJsonAst
generateJsonAst,
validateSettings,
} = require('../utils/index')
const debug = require('debug')('eslint-plugin-vue-i18n:no-html-messages')

Expand Down Expand Up @@ -45,16 +46,11 @@ function create (context) {
return {}
}

const { settings } = context
if (!settings['vue-i18n'] || !settings['vue-i18n'].localeDir) {
context.report({
loc: UNEXPECTED_ERROR_LOCATION,
message: `You need to 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation`
})
if (!validateSettings(context)) {
return {}
}

const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir)
const localeMessages = getLocaleMessages(context)
const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages)
if (!targetLocaleMessage) {
debug(`ignore ${filename} in no-html-messages`)
Expand Down
38 changes: 17 additions & 21 deletions lib/rules/no-missing-keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,79 +7,75 @@ const {
UNEXPECTED_ERROR_LOCATION,
defineTemplateBodyVisitor,
getLocaleMessages,
findMissingsFromLocaleMessages
getSettings,
findMissingsFromLocaleMessages,
validateSettings,
} = require('../utils/index')

function create (context) {
const { settings } = context
if (!settings['vue-i18n'] || !settings['vue-i18n'].localeDir) {
context.report({
loc: UNEXPECTED_ERROR_LOCATION,
message: `You need to set 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation`
})
if (!validateSettings(context)) {
return {}
}

const localeDir = settings['vue-i18n'].localeDir
const localeMessages = getLocaleMessages(localeDir)
const localeMessages = getLocaleMessages(context)

return defineTemplateBodyVisitor(context, {
"VAttribute[directive=true][key.name='t']" (node) {
checkDirective(context, localeDir, localeMessages, node)
checkDirective(context, localeMessages, node)
},

"VAttribute[directive=true][key.name.name='t']" (node) {
checkDirective(context, localeDir, localeMessages, node)
checkDirective(context, localeMessages, node)
},

"VElement[name=i18n] > VStartTag > VAttribute[key.name='path']" (node) {
checkComponent(context, localeDir, localeMessages, node)
checkComponent(context, localeMessages, node)
},

"VElement[name=i18n] > VStartTag > VAttribute[key.name.name='path']" (node) {
checkComponent(context, localeDir, localeMessages, node)
checkComponent(context, localeMessages, node)
},

CallExpression (node) {
checkCallExpression(context, localeDir, localeMessages, node)
checkCallExpression(context, localeMessages, node)
}
}, {
CallExpression (node) {
checkCallExpression(context, localeDir, localeMessages, node)
checkCallExpression(context, localeMessages, node)
}
})
}

function checkDirective (context, localeDir, localeMessages, node) {
function checkDirective (context, localeMessages, node) {
if ((node.value && node.value.type === 'VExpressionContainer') &&
(node.value.expression && node.value.expression.type === 'Literal')) {
const key = node.value.expression.value
if (!key) {
// TODO: should be error
return
}
const missings = findMissingsFromLocaleMessages(localeMessages, key, localeDir)
const missings = findMissingsFromLocaleMessages(localeMessages, key)
if (missings.length) {
missings.forEach(missing => context.report({ node, ...missing }))
}
}
}

function checkComponent (context, localeDir, localeMessages, node) {
function checkComponent (context, localeMessages, node) {
if (node.value && node.value.type === 'VLiteral') {
const key = node.value.value
if (!key) {
// TODO: should be error
return
}
const missings = findMissingsFromLocaleMessages(localeMessages, key, localeDir)
const missings = findMissingsFromLocaleMessages(localeMessages, key)
if (missings.length) {
missings.forEach(missing => context.report({ node, ...missing }))
}
}
}

function checkCallExpression (context, localeDir, localeMessages, node) {
function checkCallExpression (context, localeMessages, node) {
const funcName = (node.callee.type === 'MemberExpression' && node.callee.property.name) || node.callee.name

if (!/^(\$t|t|\$tc|tc)$/.test(funcName) || !node.arguments || !node.arguments.length) {
Expand All @@ -95,7 +91,7 @@ function checkCallExpression (context, localeDir, localeMessages, node) {
return
}

const missings = findMissingsFromLocaleMessages(localeMessages, key, localeDir)
const missings = findMissingsFromLocaleMessages(localeMessages, key)
if (missings.length) {
missings.forEach(missing => context.report({ node, ...missing }))
}
Expand Down
12 changes: 4 additions & 8 deletions lib/rules/no-unused-keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const {
findExistLocaleMessage,
getLocaleMessages,
extractJsonInfo,
generateJsonAst
generateJsonAst,
validateSettings,
} = require('../utils/index')
const debug = require('debug')('eslint-plugin-vue-i18n:no-unused-keys')

Expand Down Expand Up @@ -79,16 +80,11 @@ function create (context) {
return {}
}

const { settings } = context
if (!settings['vue-i18n'] || !settings['vue-i18n'].localeDir) {
context.report({
loc: UNEXPECTED_ERROR_LOCATION,
message: `You need to 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation`
})
if (!validateSettings(context)) {
return {}
}

const localeMessages = getLocaleMessages(settings['vue-i18n'].localeDir)
const localeMessages = getLocaleMessages(context)
const targetLocaleMessage = findExistLocaleMessage(filename, localeMessages)
if (!targetLocaleMessage) {
debug(`ignore ${filename} in no-unused-keys`)
Expand Down
38 changes: 27 additions & 11 deletions lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,16 @@ function loadLocaleMessages (pattern) {
})
}

let localeMessages = null // locale messages
let localeDir = null // locale dir

function getLocaleMessages (localeDirectory) {
if (localeDir !== localeDirectory) {
localeDir = localeDirectory
localeMessages = loadLocaleMessages(localeDir)
} else {
localeMessages = localeMessages || loadLocaleMessages(localeDir)
let localeDirCache = {} // locale messages

function getLocaleMessages (context) {
const settings = getSettings(context)

if (settings.locale && settings.messages) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need settings.locale ?
We need to cover everything all locales resources.

In about configuration name of settings.message, I think this feature is for loading resources with complicated structure. For this reason, the name should be intuitive, such as loadLocaleMessages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this design was because I misunderstood how the library currently supports multiple locales, I've provided more details below.

return [{ messages: settings.messages[settings.locale] }]
}
return localeMessages

return localeDirCache[settings.localeDir] = localeDirCache[settings.localeDir] || loadLocaleMessages(settings.localeDir)
}

function findMissingsFromLocaleMessages (localeMessages, key) {
Expand Down Expand Up @@ -106,12 +105,29 @@ function generateJsonAst (context, json, filename) {
return ast
}

function getSettings(context) {
return context.settings['vue-i18n'] || {}
}

function validateSettings(context) {
const settings = getSettings(context)
const isValid = !!(settings.locale || settings.localeDir || settings.messages)
if (!isValid) {
context.report({
loc: UNEXPECTED_ERROR_LOCATION,
message: 'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation',
})
}
return isValid
}

module.exports = {
UNEXPECTED_ERROR_LOCATION,
defineTemplateBodyVisitor,
getLocaleMessages,
findMissingsFromLocaleMessages,
findExistLocaleMessage,
extractJsonInfo,
generateJsonAst
generateJsonAst,
validateSettings,
}
20 changes: 19 additions & 1 deletion tests/lib/rules/no-missing-keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ const settings = {
}
}

const messageSettings = {
'vue-i18n': {
locale: 'en',
messages: { en: { hello: 'hello world' }},
}
}

const tester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: { ecmaVersion: 2015 }
Expand Down Expand Up @@ -60,6 +67,10 @@ tester.run('no-missing-keys', rule, {
code: `<template>
<p v-t="'hello'"></p>
</template>`
}, {
// using message settings
settings: messageSettings,
code: `$t('hello')`
}],

invalid: [{
Expand Down Expand Up @@ -106,7 +117,7 @@ tester.run('no-missing-keys', rule, {
// settings.vue-i18n.localeDir' error
code: `$t('missing')`,
errors: [
`You need to set 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation`
'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation'
]
}, {
// nested basic
Expand All @@ -118,5 +129,12 @@ tester.run('no-missing-keys', rule, {
`'missing.path' does not exist`,
`'missing.path' does not exist`
]
}, {
// using message settings
settings: messageSettings,
code: `$t('missing')`,
errors: [
`'missing' does not exist`
]
}]
})
2 changes: 1 addition & 1 deletion tests/lib/rules/no-unused-keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('no-unused-keys', () => {
.filter(message => message.ruleId === 'vue-i18n/no-unused-keys')
}).reduce((values, current) => values.concat(current), [])
.forEach(message => {
assert.equal(message.message, `You need to 'localeDir' at 'settings. See the 'eslint-plugin-vue-i18n documentation`)
assert.equal(message.message, 'You need to define locales in settings. See the eslint-plugin-vue-i18n documentation')
})
})
})
Expand Down