Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to `@escalated-dev/escalated` will be documented in this fil

## [Unreleased]

### Added
- feat: consume translations from `@escalated-dev/locale` as the canonical base source, with `src/locales/*.json` retained as local plugin overrides that win over central. Public `useI18n().t()` / `$t` API is unchanged.

## [0.7.1] - 2026-04-28

### Changed
Expand Down
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"@inertiajs/vue3": "^1.0.0 || ^2.0.0 || ^3.0.0",
"vue": "^3.3.0"
},
"dependencies": {
"@escalated-dev/locale": "github:escalated-dev/escalated-locale#v0.1.2"
},
"scripts": {
"test": "vitest run",
"lint": "eslint src/ --max-warnings 0",
Expand Down
38 changes: 30 additions & 8 deletions src/composables/useI18n.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { ref, computed } from 'vue';
import locales from '../locales/index.js';
import overrideLocales from '../locales/index.js';

// Central translations published from escalated-dev/escalated-locale.
// This is the BASE layer. Local src/locales/*.json files in this repo are
// loaded as OVERRIDES and win over the central source for any matching key.
//
// Until @escalated-dev/locale v0.1.0 ships its consolidated strings, this
// import resolves to a stub object with the same shape. Local overrides
// (src/locales/) preserve the current behavior so components keep rendering
// the strings they always rendered. After Codex finishes consolidating
// translations into the central package, the local override files can be
// trimmed (or deleted entirely) and the central source becomes authoritative.
import centralLocales from '@escalated-dev/locale';

const currentLocale = ref('en');
const customMessages = ref({});
Expand Down Expand Up @@ -55,21 +67,31 @@ export function useI18n() {
function t(key, replacements) {
const lang = currentLocale.value;

// Try custom messages for current locale
// 1. Host-app supplied messages for the current locale (highest priority).
const custom = resolve(customMessages.value[lang], key);
if (typeof custom === 'string') return applyReplacements(custom, replacements);

// Try built-in messages for current locale
const msg = resolve(locales[lang], key);
if (typeof msg === 'string') return applyReplacements(msg, replacements);
// 2. Local plugin overrides for the current locale (src/locales/*.json).
// These exist to let this repo win over the central source for any
// string the plugin needs to phrase differently.
const override = resolve(overrideLocales[lang], key);
if (typeof override === 'string') return applyReplacements(override, replacements);

// 3. Central source for the current locale (@escalated-dev/locale).
// This is the canonical base layer.
const central = resolve(centralLocales?.[lang], key);
if (typeof central === 'string') return applyReplacements(central, replacements);

// Fallback to English
// 4. English fallbacks, in the same priority order.
if (lang !== 'en') {
const customEn = resolve(customMessages.value.en, key);
if (typeof customEn === 'string') return applyReplacements(customEn, replacements);

const fallback = resolve(locales.en, key);
if (typeof fallback === 'string') return applyReplacements(fallback, replacements);
const overrideEn = resolve(overrideLocales.en, key);
if (typeof overrideEn === 'string') return applyReplacements(overrideEn, replacements);

const centralEn = resolve(centralLocales?.en, key);
if (typeof centralEn === 'string') return applyReplacements(centralEn, replacements);
}

// Return raw key
Expand Down
13 changes: 13 additions & 0 deletions src/locales/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Local locale overrides

The JSON files in this directory (`en.json`, `de.json`, …) are **local overrides** that win over the central source published by [`@escalated-dev/locale`](https://github.com/escalated-dev/escalated-locale).

The composable in `src/composables/useI18n.js` resolves keys in this order:

1. Host-app `customMessages` for the current locale
2. Local override (these JSON files) for the current locale
3. Central source (`@escalated-dev/locale`) for the current locale
4. Same three layers, but English fallback
5. Raw key

After the central package is populated with the canonical strings, files here can be trimmed to contain only the keys this plugin needs to phrase differently from the central source. Keys not present locally fall through to the central source unchanged.
Loading