Tracking
Lunaria implements a unique localization tracking system powered by Git. This guide explains how it works, how to manipulate it, and all its associated features.
How it works
Section titled “How it works”To track changes, Lunaria uses the repository’s git history to compare the latest major commit date from the source and localized version of a file. If the localization has been last changed after the source, then it is considered up-to-date. Otherwise, it is considered outdated.
A “major commit” is the name given to a commit that has significant content changes. When a major commit is merged into the tracked branch, it will trigger status changes on Lunaria. Those are predictable, and can only be one of the following:
- The source content was changed, marking localizations as outdated.
- A localization was updated, marking it as done.
By default, every commit is considered major, and to allow for certain commits to not be considered, Lunaria offers a few ways to manipulate status changes.
Set up tracking
Section titled “Set up tracking”To add files to Lunaria’s tracking system, you need to add the files field to your lunaria.config.mjs file. It will receive an array of objects of the File type, like the following example:
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({ files: [ { include: ['src/content/docs/en/**/*.md'], pattern: 'src/content/docs/@lang/@path', type: 'universal', }, ],});In this example, Lunaria will track all Markdown files within the src/content/docs directory and its subdirectories. More entries can be added to files to track different sets of files differently or to better organize them in the generated dashboard since the order in the array will be respected.
Read further to understand how all of these fields work.
include
Section titled “include”The include field expects an array of glob patterns that match all of the desired source files to be tracked.
Lunaria’s glob patterns are powered by tinyglobby, and although it’s not the place for this documentation to explain glob patterns, here are a few common snippets that you can find useful to know:
**/*.md: Matches all.mdfiles on the directory and its subdirectories.*.md: Matches all.mdfiles on the directory.**/*.{md,mdx}: Matches all.mdand.mdxfiles on the directory and its subdirectories.**/!(index).md: Matches all.mdfiles on the directory and its subdirectories, except for theindex.mdfile.
pattern
Section titled “pattern”The pattern field expects a path-to-regexp string that will be used to extract the shared path of files and infer their relation. Lunaria adds the @lang and @path placeholders to help you indicate where the locale and the rest of the path should be added in.
In very few cases, @lang and @path might not correctly represent your project’s file structure. Internally, these placeholders are replaced with slightly opinionated :lang and :path path parameters. You can also use these parameters instead of placeholders, tweaking them with prefixes, suffixes, and/or modifiers to match your project’s file structure.
For example, to support Nextra’s rather unique i18n file structure, you could use the following pattern using :path+ instead of @path:
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({ files: [ { include: ['pages/**/*.en.mdx'], pattern: 'pages/:path+.@lang.mdx', type: 'universal', }, ],});Different source and localized paths
Section titled “Different source and localized paths”When the source and localized files don’t share the same structure, pattern also accepts an object with a source pattern for the source files and a locales pattern for the localized files.
This is helpful for projects where the source content lives in the root of the content directory while localizations live in a subdirectory per locale:
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({ files: [ { include: ['src/content/docs/**/*.md'], pattern: { source: 'src/content/docs/@path', locales: 'src/content/docs/@lang/@path', }, type: 'universal', }, ],});Custom parameters
Section titled “Custom parameters”The @lang placeholder always matches the lang value of your locales, but some projects use a different value in their file paths, e.g. pt-BR instead of pt-br. For these cases, every locale can set additional parameters that become placeholders available in your patterns, prefixed with @.
The example below adds a tag parameter to each locale, used to match the file names of a dictionary with the @tag placeholder:
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({ sourceLocale: { label: 'English', lang: 'en', parameters: { tag: 'en', }, }, locales: [ { label: 'Português do Brasil', lang: 'pt-br', parameters: { tag: 'pt-BR', }, }, ], files: [ { include: ['src/i18n/en.yml'], pattern: 'src/i18n/@tag.yml', type: 'dictionary', }, ],});The type field determines how these files will be treated by Lunaria. Different types can change and augment how files are displayed in the dashboard, have different requirements (e.g. supported file types), and how their outdated/done status is calculated.
For more information, read the available types in the file types section of the configuration reference.
exclude
Section titled “exclude”Optionally, the exclude field can be added to exclude specific files from tracking. It expects an array of glob patterns that match all of the files to be ignored, for example:
import { defineConfig } from '@lunariajs/core/config';
export default defineConfig({ files: [ { include: ['src/content/docs/en/**/*.md'], pattern: 'src/content/docs/@lang/@path', type: 'universal', exclude: ['src/content/docs/**/old.md'], }, ],});Granularly enabling files for localization
Section titled “Granularly enabling files for localization”You may wish to only enable certain files for localization, e.g. only files that have been in the source locale for more than a week, or that aren’t expecting to be restructured soon.
One way of doing so would be to exclude specific files with the exclude field, but this would require you to manually update the configuration file every time a file is ready for localization.
Instead, you can use the tracking.localizableProperty available to files that accept frontmatter metadata (e.g. Markdown, MDX, Markdoc). Every file where the property is true will be added to the dashboard, and omitted otherwise:
-
Add the
tracking.localizablePropertyfield to yourlunaria.config.mjsfile, with the name of the frontmatter property that will be used to enable localization:lunaria.config.mjs import { defineConfig } from '@lunariajs/core/config';export default defineConfig({tracking: {localizableProperty: 'isLocalizable',},}); -
Add the frontmatter property to the files you want to enable for localization with the value
true:my-page.mdx ---title: My pageisLocalizable: true---# My MDX page
Manipulating status changes
Section titled “Manipulating status changes”In a few cases, it might be relevant to intervene in the tracking system to prevent undesired status changes from happening.
This is helpful when there are changes that shouldn’t mark localizations as outdated, like typo fixes in the source content, or when a change shouldn’t mark a localization as done, like updating a broken link in an otherwise outdated localization.
Ignoring commits
Section titled “Ignoring commits”To ignore all changes within a commit, you can add an ignored keyword to your commit or pull request’s title (when squash merging). By default, the keywords fix typo and lunaria-ignore will be ignored.
For example, the following commit title would be ignored:
[lunaria-ignore] Format localization filesOn the other hand, the following commit title would trigger status changes:
Add a new section on `getting-started.mdx` fileDifferent ignoredKeywords can be added, overriding the default ones:
-
Add the
tracking.ignoredKeywordsfield to yourlunaria.config.mjsfile, with an array of keywords to be ignored:lunaria.config.mjs import { defineConfig } from '@lunariajs/core/config';export default defineConfig({tracking: {ignoredKeywords: ['@ignore', '[ci]', '[format]'],},});
The ignoredKeywords feature can also be disabled completely:
-
Add the
tracking.ignoredKeywordsfield to yourlunaria.config.mjsfile, with an empty array:lunaria.config.mjs import { defineConfig } from '@lunariajs/core/config';export default defineConfig({tracking: {ignoredKeywords: [],},});
Triggering changes per-file
Section titled “Triggering changes per-file”Sometimes, a commit might include both changes that should trigger status changes and changes that shouldn’t, especially when there are circular references between files that need to be in the same pull request to avoid errors. When that’s the case, your best option is to use a tracker directive.
A tracker directive is a custom syntax added to a commit’s description with a list of files or globs separated with ; that will be considered by the tracker directive:
@lunaria-ignore:docs/en/first.mdx;docs/ja/second.mdx;docs/**/third.mdx@lunaria-track
Section titled “@lunaria-track”The @lunaria-track directive will track the changes of all the listed files, and ignore all the ones that weren’t on the same commit. For example:
@lunaria-track:src/content/docs/en/**.mdx@lunaria-ignore
Section titled “@lunaria-ignore”The @lunaria-ignore directive will ignore the changes of all the listed files, and track all the ones that weren’t on the same commit. For example:
@lunaria-ignore:src/content/docs/ja/**.mdx