Skip to content

Commit

Permalink
feat: add basic module locale merging (#1955)
Browse files Browse the repository at this point in the history
* feat: add basic module locale merging

* refactor: rewrite LocaleObject merging to be generic and reusable

* fix: register module hook type

* docs: add documentation describing registerModule hook

* test: add register module hook test
  • Loading branch information
BobbieGoede authored Mar 29, 2023
1 parent c1d4ec9 commit d898a07
Show file tree
Hide file tree
Showing 21 changed files with 439 additions and 81 deletions.
88 changes: 70 additions & 18 deletions docs/content/2.guide/13.extend-messages.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
# Extending messages hook

Nuxt hook to extend app's messages.
Nuxt hooks to extend i18n messages in your project.

---

If you're a **module author** and want that module to provide extra messages for your project, you can merge them into the normally loaded messages by using the `i18n:extend-messages` hook.
For **module authors** that want to provide messages with their modules, there are now two options to add or merge them into the normally loaded messages.

To do this, in your module's setup file listen to the Nuxt hook and push your messages. `@nuxtjs/i18n` will do the rest.
This is particularly useful if your module uses translated content and you want to offer nice default translations.

This is particularly useful if your module use translated content and you want to offer to users nice default translations.
1. [The `i18n:extend-messages` hook](#i18nextend-messages)
2. [The `i18n:registerModule` hook](#i18nregistermodule)

### `i18n:extend-messages`
In your module's setup file listen to the Nuxt `i18n:extend-messages` hook and push your messages. `@nuxtjs/i18n` will do the rest.

Example:

```ts{}[my-module-exemple/module1.ts]
```ts{}[my-module-example/module1.ts]
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('i18n:extend-messages', async (additionalMessages, localeCodes) => {
additionalMessages.push({
en: {
'my-module-exemple': {
'my-module-example': {
hello: 'Hello from external module'
}
},
fr: {
'my-module-exemple': {
'my-module-example': {
hello: 'Bonjour depuis le module externe'
}
}
Expand All @@ -36,29 +40,77 @@ export default defineNuxtModule({
```

Now the project has access to new messages and can use them through `$t('my-module-exemple.hello')`.
### `i18n:registerModule`
In your module's setup file listen to the Nuxt `i18n:registerModule` hook and register your i18n configuration, this is similar to how [lazy-load translations](./lazy-load-translations) are configured.

::alert{type="info"}
Translations added this way will be loaded after those added in your project, and before extended layers.

Example:
::code-group
::code-block{label="module.ts" active}
```ts{}[my-module-example/module.ts]
import { createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
async setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
nuxt.hook('i18n:registerModule', register => {
register({
// langDir path needs to be resolved
langDir: resolve('./lang'),
locales: [
{
code: 'en',
file: 'en.json',
},
{
code: 'fr',
file: 'fr.json',
},
]
})
})
}
})
```
::
::code-block{label="en.json"}
```json
{
"my-module-example": {
"hello": "Hello from external module"
}
}
```
::
::code-block{label="fr.json"}
```json
{
"my-module-example": {
"hello": "Bonjour depuis le module externe"
}
}
```
::
::

Now the project has access to new messages and can use them through `$t('my-module-example.hello')`.

The custom module that is use `i18n:extend-messages` hook should be inserted before nuxt i18n module.
::alert{type="info"}
These hooks will only work for modules registered before the `@nuxtjs/i18n` module.

```ts {}[nuxt.config.ts]
import CustomModule from './custom' // import your custom module
import ExampleModule from './my-module-example/module.ts' // import your custom module

export default defineNuxtConfig({
modules: [
CustomModule,
ExampleModule,
'@nuxtjs/i18n',
],
})
```

::

::alert

Because module's messages are merged with the project's ones, it's safer to prefix them.

Main project messages **will always override** the module's ones.

Because module's messages are merged with the project's ones, it's safer to prefix them. Main project messages **will always override** the module's ones.
::
36 changes: 35 additions & 1 deletion docs/content/4.API/5.nuxt.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,38 @@ export default defineNuxtModule({
}
```
See also [Extending messages hook](/guide/extend-messages)
See also [Extending messages hook](/guide/extend-messages#i18nextend-messages)
### `i18n:registerModule` Hook
- **Arguments**:
- registerModule (type: `({ langDir: string, locales: LocaleObject[] }) => void`)
```ts{}[my-module-example/module.ts]
import { createResolver, defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
async setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
nuxt.hook('i18n:registerModule', register => {
register({
// langDir path needs to be resolved
langDir: resolve('./lang'),
locales: [
{
code: 'en',
file: 'en.json',
},
{
code: 'fr',
file: 'fr.json',
},
]
})
})
}
})
```
See also [Extending messages hook](/guide/extend-messages#i18nregistermodule)
32 changes: 32 additions & 0 deletions playground/layer-module/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createResolver, defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
async setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
nuxt.hook('i18n:registerModule', register => {
register({
langDir: resolve('./locales'),
locales: [
{
code: 'en',
iso: 'en-US',
file: 'en.json',
name: 'English'
},
{
code: 'fr',
iso: 'fr-FR',
file: 'fr.json',
name: 'Francais'
},
{
code: 'nl',
iso: 'nl-NL',
file: 'nl.json',
name: 'Nederlands'
}
]
})
})
}
})
3 changes: 3 additions & 0 deletions playground/layer-module/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"moduleLayerText": "This is a merged module layer locale key"
}
3 changes: 3 additions & 0 deletions playground/layer-module/locales/fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"moduleLayerText": "This is a merged module layer locale key in French"
}
3 changes: 3 additions & 0 deletions playground/layer-module/locales/nl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"moduleLayerText": "This is a merged module layer locale key in Dutch"
}
34 changes: 34 additions & 0 deletions playground/layer-module/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// import type { NuxtApp } from 'nuxt/dist/app/index'

// https://nuxt.com/docs/guide/directory-structure/nuxt.config
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
langDir: 'locales',
lazy: true,
baseUrl: 'http://localhost:3000',
locales: [
{
code: 'en',
iso: 'en-US',
file: 'en.json',
// domain: 'localhost',
name: 'English'
},
{
code: 'fr',
iso: 'fr-FR',
file: 'fr.json',
// domain: 'localhost',
name: 'Francais'
},
{
code: 'nl',
iso: 'nl-NL',
file: 'nl.json',
// domain: 'localhost',
name: 'Nederlands'
}
]
}
})
31 changes: 20 additions & 11 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import Module1 from './module1'
import LayerModule from './layer-module'
import type { NuxtApp } from 'nuxt/dist/app/index'

// https://nuxt.com/docs/guide/directory-structure/nuxt.config
export default defineNuxtConfig({
extends: ['layers/i18n-layer'],
modules: [Module1, '@nuxtjs/i18n', '@nuxt/devtools'],
modules: [
(_, nuxt) => {
console.log(nuxt.options._installedModules)
},
Module1,
LayerModule,
'@nuxtjs/i18n',
'@nuxt/devtools'
],
vite: {
build: {
minify: false
Expand All @@ -19,7 +28,7 @@ export default defineNuxtConfig({
// }
// }
// },

debug: false,
i18n: {
experimental: {
jsTsFormatResource: true
Expand Down Expand Up @@ -61,7 +70,7 @@ export default defineNuxtConfig({
}
],
// trailingSlash: true,
debug: true,
debug: false,
defaultLocale: 'en',
// strategy: 'no_prefix',
// strategy: 'prefix',
Expand All @@ -80,14 +89,14 @@ export default defineNuxtConfig({
},
// differentDomains: true,
// skipSettingLocaleOnNavigate: true,
detectBrowserLanguage: false,
// detectBrowserLanguage: {
// useCookie: true,
// // alwaysRedirect: true
// // cookieKey: 'i18n_redirected',
// // // cookieKey: 'my_custom_cookie_name',
// // redirectOn: 'root'
// },
// detectBrowserLanguage: false,
detectBrowserLanguage: {
useCookie: true
// alwaysRedirect: true
// cookieKey: 'i18n_redirected',
// // cookieKey: 'my_custom_cookie_name',
// redirectOn: 'root'
},
// vueI18n: './vue-i18n.options.ts'
vueI18n: {
legacy: false,
Expand Down
32 changes: 32 additions & 0 deletions specs/fixtures/basic_layer/layer-module/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createResolver, defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
async setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
nuxt.hook('i18n:registerModule', register => {
register({
langDir: resolve('./locales'),
locales: [
{
code: 'en',
iso: 'en-US',
file: 'en.json',
name: 'English'
},
{
code: 'fr',
iso: 'fr-FR',
file: 'fr.json',
name: 'Francais'
},
{
code: 'nl',
iso: 'nl-NL',
file: 'nl.json',
name: 'Nederlands'
}
]
})
})
}
})
3 changes: 3 additions & 0 deletions specs/fixtures/basic_layer/layer-module/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"moduleLayerText": "This is a merged module layer locale key"
}
3 changes: 3 additions & 0 deletions specs/fixtures/basic_layer/layer-module/locales/fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"moduleLayerText": "This is a merged module layer locale key in French"
}
3 changes: 3 additions & 0 deletions specs/fixtures/basic_layer/layer-module/locales/nl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"moduleLayerText": "This is a merged module layer locale key in Dutch"
}
34 changes: 34 additions & 0 deletions specs/fixtures/basic_layer/layer-module/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// import type { NuxtApp } from 'nuxt/dist/app/index'

// https://nuxt.com/docs/guide/directory-structure/nuxt.config
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
langDir: 'locales',
lazy: true,
baseUrl: 'http://localhost:3000',
locales: [
{
code: 'en',
iso: 'en-US',
file: 'en.json',
// domain: 'localhost',
name: 'English'
},
{
code: 'fr',
iso: 'fr-FR',
file: 'fr.json',
// domain: 'localhost',
name: 'Francais'
},
{
code: 'nl',
iso: 'nl-NL',
file: 'nl.json',
// domain: 'localhost',
name: 'Nederlands'
}
]
}
})
Loading

0 comments on commit d898a07

Please sign in to comment.