Skip to content

Upgrade Lunaria

To get started, update your project’s version of @lunariajs/core to the latest version using your package manager:

Terminal window
npm install @lunariajs/core@latest

Lunaria v0.2 includes breaking changes, as well as the removal of some previously deprecated features. See the Lunaria changelog for full release notes.

Lunaria was previously configured with a lunaria.config.json file.

Lunaria v0.2 replaces it with a JavaScript or TypeScript configuration file, allowing you to use functions (e.g. for the renderer and integrations) and to get IntelliSense support through the defineConfig() helper instead of the JSON Schema.

As a consequence, the $schema property and the config.schema.json file shipped with @lunariajs/core have been removed.

  1. Create a new lunaria.config.mjs file at the root of your project, wrapping your existing configuration with defineConfig():

    lunaria.config.json
    {
    "$schema": "./node_modules/@lunariajs/core/config.schema.json",
    "repository": {
    "name": "me/cool-docs"
    },
    "defaultLocale": { "label": "English", "lang": "en" },
    "locales": [{ "label": "Português", "lang": "pt" }]
    }
    lunaria.config.mjs
    import { defineConfig } from '@lunariajs/core/config';
    export default defineConfig({
    repository: {
    name: 'me/cool-docs',
    },
    sourceLocale: { label: 'English', lang: 'en' },
    locales: [{ label: 'Português', lang: 'pt' }],
    });
  2. Update the properties that were renamed or restructured in v0.2, as described in the sections below.

  3. Delete your lunaria.config.json file. If you were using the --config CLI option, update it to point to the new file.

Renamed: defaultLocale is now sourceLocale

Section titled “Renamed: defaultLocale is now sourceLocale”

The defaultLocale configuration property has been renamed to sourceLocale to better describe its purpose as the locale of the source content that is going to be localized.

Rename the defaultLocale property in your Lunaria configuration:

lunaria.config.mjs
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({
defaultLocale: { label: 'English', lang: 'en' },
sourceLocale: { label: 'English', lang: 'en' },
});

Changed: files entries use include and exclude

Section titled “Changed: files entries use include and exclude”

The location and ignore properties of each files entry have been renamed to include and exclude, respectively. include now expects an array of glob patterns instead of a single string.

In Lunaria v0.1, location had to match the files of every locale. In v0.2, include should match only the source files, and the paths of their localizations are inferred from the pattern instead. Any localized file matched by include is ignored with a warning.

Rename location to include and ignore to exclude in every files entry, and narrow your globs to your source files:

lunaria.config.mjs
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({
files: [
{
location: 'src/content/docs/**/*.mdx',
include: ['src/content/docs/en/**/*.mdx'],
pattern: 'src/content/docs/@lang/@path',
ignore: ['src/content/docs/**/old.mdx'],
exclude: ['src/content/docs/**/old.mdx'],
type: 'universal',
},
],
});

In Lunaria v0.1, the @lang placeholder of a pattern was optional, allowing a single pattern to match both source files without a locale directory (e.g. src/content/docs/guide.mdx) and localized files with one (e.g. src/content/docs/pt/guide.mdx).

In Lunaria v0.2, @lang strictly matches the lang of your locales. Projects where the source and localized files follow different structures must use the new pattern object with separate source and locales patterns.

The @locales placeholder has also been removed.

If your source files don’t include the locale in their path, replace the pattern string with an object:

lunaria.config.mjs
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({
files: [
{
include: ['src/content/docs/**/*.mdx'],
pattern: 'src/content/docs/@lang/@path',
pattern: {
source: 'src/content/docs/@path',
locales: 'src/content/docs/@lang/@path',
},
type: 'universal',
},
],
});

Read more about different source and localized paths in the tracking guide.

In Lunaria v0.1, the optionalKeys property of dictionary file entries was a record of shared paths with an array of top-level keys to be considered optional.

In Lunaria v0.2, optionalKeys applies to every file matched by the entry and mirrors the structure of your dictionaries: a key set to true is optional, including any keys nested inside of it. This allows nested keys to be optional now that key completion is checked for nested keys as well.

Convert the arrays of keys into an object with the keys set to true. If different files of the same entry had different optional keys, split them into separate files entries:

lunaria.config.mjs
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({
files: [
{
include: ['ui/en/nav.json'],
pattern: 'ui/@lang/@path',
type: 'dictionary',
optionalKeys: {
'ui/nav.json': ['footer', 'sidebar'],
'ui/ui.yml': ['search'],
},
optionalKeys: {
footer: true,
sidebar: true,
},
},
],
});

Moved: ignoreKeywords and localizableProperty into tracking

Section titled “Moved: ignoreKeywords and localizableProperty into tracking”

The ignoreKeywords and localizableProperty top-level properties have been moved into a new tracking object, with ignoreKeywords also renamed to ignoredKeywords.

Move both properties into tracking and rename ignoreKeywords:

lunaria.config.mjs
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({
ignoreKeywords: ['i18nIgnore', 'en-only'],
localizableProperty: 'i18nReady',
tracking: {
ignoredKeywords: ['i18nIgnore', 'en-only'],
localizableProperty: 'i18nReady',
},
});

Changed: renderer is now part of the configuration

Section titled “Changed: renderer is now part of the configuration”

In Lunaria v0.1, the renderer property was the path to a separate renderer.config.(c/m)js or renderer.config.(c/m)ts file.

Since the Lunaria configuration is now a JavaScript module, renderer receives the renderer configuration object directly.

Move your renderer configuration into the renderer property of your Lunaria configuration, or import your existing renderer file into it:

lunaria.config.mjs
import { defineConfig } from '@lunariajs/core/config';
import renderer from './renderer.config.mjs';
export default defineConfig({
renderer: './renderer.config.mjs',
renderer,
});

Read more about the defineRendererConfig() helper in the Renderer API reference.

Changed: renderer components receive the new status format

Section titled “Changed: renderer components receive the new status format”

The status parameter passed to overrides components (body, statusByLocale, and statusByFile) follows the new status format. Each entry now exposes its source file as source and its localizations as an array, instead of sharedPath, sourceFile, and a localizations record keyed by locale.

Update your custom components to read from the new properties:

lunaria.config.mjs
import { html } from '@lunariajs/core';
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({
renderer: {
overrides: {
body: (config, status) => html`<ul>${status.map((s) => html`<li>${s.sharedPath}</li>`)}</ul>`,
body: (config, status) => html`<ul>${status.map((entry) => html`<li>${entry.source.path}</li>`)}</ul>`,
},
},
});

Changed: shallow repositories are no longer cloned automatically

Section titled “Changed: shallow repositories are no longer cloned automatically”

In Lunaria v0.1, running in a shallow repository (e.g. the default checkout of most CI environments) made Lunaria clone the full git history of your repository into the cloneDir directory.

In Lunaria v0.2, Lunaria fails with an error when the repository is shallow, since the missing history would produce an inaccurate status.

Deployments on Netlify and Vercel are detected and have their missing git data fetched automatically.

Ensure the full git history is available wherever you run Lunaria. On GitHub Actions, set fetch-depth: 0 in the checkout step:

.github/workflows/lunaria.yml
- name: Checkout
uses: actions/checkout@v7
with:
# Makes the action clone the entire git history
fetch-depth: 0

On other platforms, run git fetch --unshallow before building your dashboard.

In Lunaria v0.1, dictionary file entries supported Markdown, MDX, and Markdoc files, using their frontmatter as the dictionary.

Lunaria v0.2 no longer supports these formats as dictionaries. YAML dictionaries are now parsed as whole YAML documents, and gettext .po and .pot files are now supported.

Track Markdown, MDX, and Markdoc files using the universal type instead, or move the localized values into a JSON, YAML, or JavaScript/TypeScript dictionary:

lunaria.config.mjs
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({
files: [
{
include: ['src/content/docs/en/**/*.mdx'],
pattern: 'src/content/docs/@lang/@path',
type: 'dictionary',
type: 'universal',
},
],
});

Changed: dictionary key completion checks nested keys

Section titled “Changed: dictionary key completion checks nested keys”

In Lunaria v0.1, only the top-level keys of a dictionary were compared to check if a localization was complete.

Lunaria v0.2 compares every nested key, and missing keys are listed in the dashboard as dot-separated paths, e.g. nav.home.

No changes are required, but localizations with missing nested keys that were previously considered done will now be marked as outdated. Update the localizations or mark the keys as optional with optionalKeys.

Removed: @tracker-major and @tracker-minor directives

Section titled “Removed: @tracker-major and @tracker-minor directives”

The @tracker-major and @tracker-minor tracker directives, deprecated in Lunaria v0.1.0, have been removed.

Use the @lunaria-track and @lunaria-ignore directives instead in new commits. Previous commits using the removed directives will be considered as regular commits, which may change the status of the files they affect.

Read more about tracker directives in the tracking guide.

The lunaria sync command, which filled the defaultLocale, locales, and files fields based on your Starlight or VitePress configuration, has been removed along with its --package and --skip-questions options.

Set the sourceLocale, locales, and files fields of your configuration manually, following the Configuration Reference.

Since the configuration is now a JavaScript module, you can also import and reuse values from your framework’s configuration file, or write an integration to set them automatically for you.

The lunaria stdout command, which logged your configuration and status in the console, has been removed.

Use the Runtime API to get your configuration and status programmatically:

import { createLunaria } from '@lunariajs/core';
const lunaria = await createLunaria();
const status = await lunaria.getFullStatus();

The --skip-status option of lunaria build has been removed.

Lunaria v0.2 caches the git data of your tracked files between builds in the cacheDir directory, so rebuilding your dashboard is fast without skipping the status.

Remove the --skip-status option from your scripts. To ignore the cache and build the status from scratch, use the new --force option:

package.json
"scripts": {
"lunaria:rebuild": "lunaria build --skip-status",
"lunaria:rebuild": "lunaria build --force",
}

The status.json file written by lunaria build and the status returned by the Runtime API follow a new format. Each entry now contains the matching files entry properties, a source object, and an array of localizations with a status of 'up-to-date', 'outdated', or 'missing'.

The git data of each file is available as git.latestCommit and git.latestTrackedCommit, replacing lastChange, lastMajorChange, and the other lastMajor* properties.

The gitHostingFileURL and gitHostingHistoryURL properties are no longer part of the status.

status.json
{
"sharedPath": "src/content/docs/guide.mdx",
"sourceFile": {
"lang": "en",
"path": "src/content/docs/en/guide.mdx",
"git": { "lastMajorChange": "2024-01-01T00:00:00.000Z" },
"gitHostingFileURL": "https://github.com/me/cool-docs/blob/main/src/content/docs/en/guide.mdx"
},
"localizations": {
"pt": {
"lang": "pt",
"path": "src/content/docs/pt/guide.mdx",
"isMissing": false,
"isOutdated": true,
"git": { "lastMajorChange": "2023-12-01T00:00:00.000Z" },
"meta": { "type": "universal" }
}
}
}
{
"include": ["src/content/docs/en/**/*.mdx"],
"pattern": "src/content/docs/@lang/@path",
"type": "universal",
"source": {
"lang": "en",
"path": "src/content/docs/en/guide.mdx",
"git": {
"latestCommit": { "date": "2024-01-01T00:00:00.000Z", "message": "Update guide" },
"latestTrackedCommit": { "date": "2024-01-01T00:00:00.000Z", "message": "Update guide" }
}
},
"localizations": [
{
"lang": "pt",
"path": "src/content/docs/pt/guide.mdx",
"status": "outdated",
"type": "universal",
"git": {
"latestCommit": { "date": "2023-12-01T00:00:00.000Z", "message": "Add guide" },
"latestTrackedCommit": { "date": "2023-12-01T00:00:00.000Z", "message": "Add guide" }
}
}
]
}

Update any scripts or integrations reading status.json or the Runtime API status to the new format.

Git hosting links can be generated with the gitHostingLinks() method of a Lunaria instance.

The lunaria() function, which returned the localization status for a configuration object, has been replaced by createLunaria(), which returns a Lunaria instance with methods to get the status of all or individual files.

Replace calls to lunaria() with createLunaria() followed by getFullStatus():

import { lunaria } from '@lunariajs/core';
import { createLunaria } from '@lunariajs/core';
const status = await lunaria(config);
const lunaria = await createLunaria({ config });
const status = await lunaria.getFullStatus();

The config is optional. When omitted, createLunaria() loads your lunaria.config.* file automatically.