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

Support custom params in both component and directive #36

Merged
merged 1 commit into from
Jul 25, 2017
Merged
Show file tree
Hide file tree
Changes from all 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
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,12 @@ in Vue 2, we have to use another set of delimiters. Instead of the
<translate translate-context="Verb">Foo</translate>
```

#### Custom parameters

```html
<translate :translate-params="{name: userFullName}">Foo %{name}</translate>
```

#### Comment

```html
Expand All @@ -326,10 +332,10 @@ in Vue 2, we have to use another set of delimiters. Instead of the
It is quite tricky to get raw HTML of a Vue component, so if you need
to include HTML content in the translations you may use the provided directive.

The directive has the same set of capabilities as the component.
The directive has the same set of capabilities as the component, **except for translate-params** which should be passed in as an expression.

```html
<p v-translate :translate-n="count" translate-plural="<strong>%{ count }</strong> cars" translate-comment="My comment for translators"><strong>%{ count }</strong> car</translate>
<p v-translate='{count: carNumbers}' :translate-n="count" translate-plural="<strong>%{ count }</strong> cars" translate-comment="My comment for translators"><strong>%{ count }</strong> car</p>
```

**Caveat when using v-translate with interpolation**
Expand All @@ -347,7 +353,29 @@ changed, but you can skip unnecessary updates by comparing the binding's
current and old values...

```html
<p v-translate='count + brand' :translate-n="count" translate-plural="<strong>%{ count }</strong> %{brand} cars" translate-comment="My comment for translators"><strong>%{ count }</strong> %{brand} car</translate>
<p v-translate='{count: count, brand: brand}' :translate-n="count" translate-plural="<strong>%{ count }</strong> %{brand} cars" translate-comment="My comment for translators"><strong>%{ count }</strong> %{brand} car</p>
```

**Caveat when using either the component '<translate>' or directive 'v-translate' with interpolation inside v-for**

It's not possible (yet) to access the scope within `v-for`, example:

```html
<p>
<translate v-for='name in names'>Hello %{name}</translate>
<span v-for='name in names' v-translate>Hello %{name}</span>
</p>
```

Will result in all `Hello %{name}` being rendered as `Hello name`

You need to pass in custom parameters for it to work:

```html
<p>
<translate v-for='name in names' :translate-params='{name: name}'>Hello %{name}</translate>
<span v-for='name in names' v-translate='{name: name}'>Hello %{name}</span>
</p>
```

**Caveat when using v-translate with Vue components or Vue-specific attributes**
Expand Down
13 changes: 12 additions & 1 deletion src/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ export default {
type: String,
required: false,
},
translateParams: {
type: Object,
required: false,
},
// `translateComment` is used exclusively by `easygettext`'s `gettext-extract`.
translateComment: {
type: String,
Expand All @@ -70,7 +74,14 @@ export default {
this.isPlural ? this.translatePlural : null,
this.$language.current
)
return this.$gettextInterpolate(translation, this.$parent)

let context = this.$parent

if (this.translateParams) {
context = Object.assign({}, this.$parent, this.translateParams)
}

return this.$gettextInterpolate(translation, context)
},
},

Expand Down
11 changes: 10 additions & 1 deletion src/directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ const updateTranslation = (el, binding, vnode) => {
let translateN = attrs['translate-n']
let translatePlural = attrs['translate-plural']
let isPlural = translateN !== undefined && translatePlural !== undefined
let context = vnode.context

if (!isPlural && (translateN || translatePlural)) {
throw new Error('`translate-n` and `translate-plural` attributes must be used together:' + msgid + '.')
}

if (!_Vue.config.getTextPluginSilent && attrs['translate-params']) {
console.warn(`\`translate-params\` is required as an expression for v-translate directive. Please change to \`v-translate='params'\`: ${msgid}`)
}

if (binding.value && typeof binding.value === 'object') {
context = Object.assign({}, vnode.context, binding.value)
}

let translation = translate.getTranslation(
msgid,
translateN,
Expand All @@ -25,7 +34,7 @@ const updateTranslation = (el, binding, vnode) => {
el.dataset.currentLanguage
)

let msg = interpolate(translation, vnode.context)
let msg = interpolate(translation, context)

el.innerHTML = msg

Expand Down
22 changes: 22 additions & 0 deletions test/specs/component.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ describe('translate component tests', () => {
expect(vm.$el.innerHTML.trim()).to.equal('<span>Bonjour John Doe</span>')
})

it('allows custom params for interpolation', () => {
Vue.config.language = 'fr_FR'
let vm = new Vue({
template: '<p><translate :translate-params="{name: someNewNameVar}">Hello %{ name }</translate></p>',
data: {
someNewNameVar: 'John Doe',
},
}).$mount()
expect(vm.$el.innerHTML.trim()).to.equal('<span>Bonjour John Doe</span>')
})

it('allows interpolation within v-for with custom params', () => {
Vue.config.language = 'fr_FR'
let vm = new Vue({
template: '<p><translate v-for="name in names" :translate-params="{name: name}">Hello %{ name }</translate></p>',
data: {
names: ['John Doe', 'Chester'],
},
}).$mount()
expect(vm.$el.innerHTML.trim()).to.equal('<span>Bonjour John Doe</span><span>Bonjour Chester</span>')
})

it('translates plurals', () => {
Vue.config.language = 'fr_FR'
let vm = new Vue({
Expand Down
43 changes: 43 additions & 0 deletions test/specs/directive.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,49 @@ describe('translate directive tests', () => {
expect(vm.$el.innerHTML).to.equal('Bonjour <strong>John Doe</strong>')
})

it('allows custom params for interpolation', () => {
Vue.config.language = 'fr_FR'
let vm = new Vue({
template: '<p v-translate="{name: someNewNameVar}">Hello <strong>%{ name }</strong></p>',
data: {
someNewNameVar: 'John Doe',
},
}).$mount()
expect(vm.$el.innerHTML.trim()).to.equal('Bonjour <strong>John Doe</strong>')
})

it('allows interpolation within v-for with custom params', () => {
Vue.config.language = 'fr_FR'
let names = ['John Doe', 'Chester']
let vm = new Vue({
template: '<p><span v-for="name in names" v-translate="{name: name}">Hello <strong>%{ name }</strong></span></p>',
data: {
names,
},
}).$mount()
let html = vm.$el.innerHTML.trim()
let missedName = names.some((name) => {
if (html.indexOf(name) === -1) {
return true
}
})
expect(missedName).to.equal(false)
})

it('logs a warning in the console if translate-params is used', () => {
console.warn = sinon.spy(console, 'warn')
Vue.config.language = 'fr_FR'
let vm = new Vue({
template: '<p v-translate :translate-params="{name: someNewNameVar}">Hello <strong>%{ name }</strong></p>',
data: {
someNewNameVar: 'John Doe',
},
}).$mount()
expect(vm.$el.innerHTML.trim()).to.equal('Bonjour <strong>name</strong>')
expect(console.warn).called
console.warn.restore()
})

it('updates a translation after a data change', (done) => {
Vue.config.language = 'fr_FR'
let vm = new Vue({
Expand Down