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

<i18n-t> message scope resolution should start at current component #729

Closed
4 tasks done
semiaddict opened this issue Oct 8, 2021 · 2 comments · Fixed by #1416
Closed
4 tasks done

<i18n-t> message scope resolution should start at current component #729

semiaddict opened this issue Oct 8, 2021 · 2 comments · Fixed by #1416
Labels
i18n-t 🔨 p3-minor-bug Priority 3: a bug in an edge case that only affects very specific usage Type: Bug Bug or Bug fixes

Comments

@semiaddict
Copy link

semiaddict commented Oct 8, 2021

Reporting a bug?

If a child component declares i18n messages, i18n-t will not find the parent messages.
It seems to stop searching in the hierarchy once it finds a component with i18n messages.

Example, in the C1 component below, the translation keys hello and world should use the component's i18n messages, even if C2 and C3 declare their own i18n messages.

C1.vue:

<template>
  <div>
    C1:
    <div>{{ $t("hello", { world: $t("world") }) }}</div>
    <i18n-t keypath="hello" tag="div">
      <template #world>
        <strong>{{ $t("world") }}</strong>
      </template>
    </i18n-t>

    <br />

    <C2>
      <div>{{ $t("hello", { world: $t("world") }) }}</div>
      <i18n-t keypath="hello" tag="div">
        <template #world>
          <strong>{{ $t("world") }}</strong>
        </template>
      </i18n-t>

      <C3>
      <div>{{ $t("hello", { world: $t("world") }) }}</div>
      <i18n-t keypath="hello" tag="div">
        <template #world>
          <strong>{{ $t("world") }}</strong>
        </template>
      </i18n-t>
      </C3>
    </C2>
  </div>
</template>

<script>
import C2 from "./C2";
import C3 from "./C3";
export default {
  components: {
    C2,
    C3,
  },
  i18n: {
    messages: {
      en: {
        hello: "Hello {world}",
        world: "world!",
      },
    },
  },
};
</script>

C2.vue:

<template>
  <div>C2 slot: <slot></slot></div>
</template>

<script>
export default {
  i18n: {
    messages: {
      en: {
        goodbuy: "Goodbuy!",
      },
    },
  },
};
</script>

C3.vue:

<template>
  <div>C3 slot: <slot></slot></div>
</template>

<script>
export default {
  i18n: {
    messages: {
      en: {
        hello: "Hello {world} - C3",
        world: "world! - C3",
      },
    },
  },
};
</script>

However, in the block on the C1 component, the keys hello and world are not resolved, as they are not found in C2, and in the block on the C1 component, the keys resolve to the values found in the C3 component.

Originally posted by @semiaddict in #708 (comment)

Expected behavior

In both cases, the hello and world should resolve to C1's values.

Reproduction

A reproduction example can be found in branch issue-708 of https://github.com/semiaddict/vue-i18n-transition-bug/tree/issue-708

System Info

System:
  OS: Linux 4.19 Debian GNU/Linux 9 (stretch) 9 (stretch)
  CPU: (8) x64 Intel(R) Core(TM) i7-4712HQ CPU @ 2.30GHz
  Memory: 2.80 GB / 7.77 GB
  Container: Yes
  Shell: 4.4.12 - /bin/bash
Binaries:
  Node: 14.16.0 - ~/.nvm/versions/node/v14.16.0/bin/node
  Yarn: 1.22.15 - ~/.nvm/versions/node/v14.16.0/bin/yarn
  npm: 7.24.1 - ~/.nvm/versions/node/v14.16.0/bin/npm
npmPackages:
  vue: ^3.2.6 => 3.2.19 
  vue-i18n: ^9.1.8 => 9.1.9

Screenshot

No response

Additional context

No response

Validations

@semiaddict semiaddict added the Status: Review Needed Request for review comments label Oct 8, 2021
@kazupon
Copy link
Member

kazupon commented Oct 11, 2021

Thank you for your reporting!

we need to revise the internal structure of vue-i18n a bit, so to solve this issue.
And we need to investigate if Vue provides a way to know where the i18n-t component was resolved in the slot.

This issue resolving is going to take some more time.

@kazupon kazupon added Status: In Progress Work in Progress Type: Bug Bug or Bug fixes and removed Status: Review Needed Request for review comments labels Oct 11, 2021
@kazupon kazupon added 🔨 p3-minor-bug Priority 3: a bug in an edge case that only affects very specific usage and removed Status: In Progress Work in Progress labels Nov 15, 2022 — with Volta.net
@coxy
Copy link

coxy commented Dec 21, 2022

As a workaround for this issue this is working for me:

import { createApp, getCurrentInstance, withCtx, h } from 'vue'
import { createI18n, Translation } from 'vue-i18n'
import App from './App'

const app = createApp(App)

const i18n = createI18n({
  locale: 'en',
  //...messages
})

app.use(i18n, { globalInstall: false })

// Change render ctx of <i18n-t>
function TranslationWithCtx(props, { slots }) {
  const inst = getCurrentInstance()
  const componentCtx = inst?.vnode?.ctx
  if (componentCtx) {
    inst.parent = componentCtx
  }
  return withCtx(() => h(Translation, props, slots), inst)()
}
app.component(Translation.name, TranslationWithCtx)

app.mount('#app')

@kazupon I'm not sure if the above is useful for the fix, but It seems you can get the base component render context from the slot context using getCurrentInstance().vnode.ctx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
i18n-t 🔨 p3-minor-bug Priority 3: a bug in an edge case that only affects very specific usage Type: Bug Bug or Bug fixes
Projects
None yet
3 participants