Localization

The library brings no i18n stack of its own: the locale, the dictionaries and where the choice is stored stay with the application. Three languages ship.

Machine-translated, not yet reviewed. Read the original

The package neither imposes a separate i18n stack on the application nor creates an instance of its own. The locale, the fallback locale, where the chosen language is stored and how the dictionaries are merged are the application’s job; the library only asks it for a translation by key.

How it works

  1. The component asks for a string by a key such as gr.pagination.prev.
  2. If a translation exists, it is used.
  3. If the layer is not wired up or returned the key itself, the component falls back to its built-in text.

The third step matters more than it looks: a missing translation does not break the interface. The package can be adopted gradually and some service strings moved into dictionaries later — the components keep working in English.

What ships

The library carries dictionaries for three languages: English, Spanish and Russian. All three are complete — the key sets are compared by one of the package’s gates rather than by eye.

The portal you are reading speaks two languages while the library speaks three. That is not an error: the Spanish dictionary of the core is complete and working, there is simply no Spanish documentation yet.

Wiring it up

The recommended layer is @feugene/fint-i18n: it is declared as an optional peer dependency and sits well with an approach where the application owns everything. If the project already has a mature i18n, the package fits into that one too.

ts
import { createFintI18n } from '@feugene/fint-i18n/core'
import { installI18n } from '@feugene/fint-i18n/vue'
import { GRANULARITY_I18N_BLOCK, en, ru } from '@feugene/granularity/i18n'

const i18n = createFintI18n({
  locale: 'ru',
  fallbackLocale: 'en',
  loaders: [en, ru],
})

i18n.registerBlocks([GRANULARITY_I18N_BLOCK])
await i18n.loadUsedBlocks('ru')

// Without this the package cannot find the instance through provide/inject
// and stays on its built-in texts.
installI18n(app, i18n)

The subpath @feugene/granularity/i18n hands out the gr block, the lazy en, es and ru loaders and the adapter key with its types. Per-locale loaders are exactly what you want in production: the bundler shakes out the unused languages. The aggregate of every locale at once lives separately, in @feugene/granularity/i18n/all, and is meant for demos, e2e and tooling.

Companion packages

Every companion has a string block of its own — grChrono, GR_MEDIA_I18N_BLOCK and so on — and they are wired into the same instance, next to the main one:

ts
import { GRANULARITY_I18N_BLOCK, en as coreEn, ru as coreRu } from '@feugene/granularity/i18n'
import { GR_CHRONO_I18N_BLOCK, en, ru } from '@feugene/granularity-chrono/i18n'

const i18n = createFintI18n({ locale: 'ru', fallbackLocale: 'en', loaders: [coreEn, coreRu, en, ru] })
i18n.registerBlocks([GRANULARITY_I18N_BLOCK, GR_CHRONO_I18N_BLOCK])

One i18n layer for the whole application — the product screens and the design system alike.

What does not come from dictionaries

The calendar, the time and relative dates take everything locale-dependent from Intl: month and weekday names, the first day of the week, the parsing order of a date, the 12- or 24-hour default. The dictionary carries interface strings only — labels, aria-labels, panel titles.

The practical consequence: the date components speak every language the engine knows, not the three listed above.

Overriding strings

Labels, buttons, aria-labels and service messages are changed in the application’s dictionary, not by forking the package. That keeps the terminology under a single control and stops upgrades from turning into conflict resolution.

Changing the language, and the provider

GrConfigProvider takes a locale prop, but that is a request for the adapter to switch, not the source of truth: the provider neither stores the locale nor substitutes it. The adapter itself is handed down through a facade rather than by value — so an adapter created asynchronously (the ordinary way a locale loads) reaches the components once it appears, and replacing the adapter on a language change re-renders the strings. See configuration.

Last reviewed: 2026-09-01