Skip to content

Commit f136cea

Browse files
committed
chore: format
1 parent 96ac8a5 commit f136cea

File tree

5 files changed

+1231
-4
lines changed

5 files changed

+1231
-4
lines changed

inject-locale.md

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
# Inject locale
2+
3+
## Introduction
4+
5+
When your translation files include locale codes as data values, such as `"locale": "en"` or `"lang": "fr"`, these codes create two problems. First, they are redundant because the file's locale is already determined by its location or filename. Second, if sent to translation services, they could be mistranslated or increase translation costs unnecessarily.
6+
7+
The inject locale feature solves both problems. It automatically removes locale codes before translation and re-inserts them afterward, ensuring the codes always match each file's actual locale without manual intervention.
8+
9+
## What inject locale does
10+
11+
Inject locale manages specific fields in your translation files that contain locale codes. You specify which fields to manage using key patterns, and Lingo handles the rest during the translation process.
12+
13+
The feature operates in two phases. During the reading phase, Lingo identifies fields where the value matches the current locale and temporarily removes them. During the writing phase, Lingo re-inserts these fields with the appropriate locale code for each target language.
14+
15+
## Supported bucket types
16+
17+
Inject locale works with these bucket types:
18+
19+
- json
20+
- json5
21+
- jsonc
22+
- json-dictionary
23+
24+
Other bucket types do not support this feature.
25+
26+
## Configuration
27+
28+
Add the `injectLocale` option to your bucket configuration in `i18n.json`. The value is an array of key patterns that specify which fields contain locale codes.
29+
30+
```json
31+
{
32+
"version": 1.9,
33+
"locale": {
34+
"source": "en",
35+
"targets": ["fr", "de", "es"]
36+
},
37+
"buckets": {
38+
"json": {
39+
"include": ["locales/[locale].json"],
40+
"injectLocale": ["locale"]
41+
}
42+
}
43+
}
44+
```
45+
46+
In this configuration, any field named `locale` that contains a locale code will be automatically managed.
47+
48+
## Key patterns
49+
50+
Key patterns specify which fields to manage. Patterns use dot notation for nested fields and support wildcards for flexible matching.
51+
52+
### Simple patterns
53+
54+
Simple patterns match specific fields by name.
55+
56+
**Top-level field:**
57+
58+
```json
59+
{
60+
"injectLocale": ["locale"]
61+
}
62+
```
63+
64+
This matches:
65+
66+
```json
67+
{
68+
"locale": "en"
69+
}
70+
```
71+
72+
**Nested field:**
73+
74+
```json
75+
{
76+
"injectLocale": ["meta.locale"]
77+
}
78+
```
79+
80+
This matches:
81+
82+
```json
83+
{
84+
"meta": {
85+
"locale": "en"
86+
}
87+
}
88+
```
89+
90+
**Multiple fields:**
91+
92+
```json
93+
{
94+
"injectLocale": ["locale", "lang", "meta.language"]
95+
}
96+
```
97+
98+
This matches any of these fields if their value is a locale code.
99+
100+
### Wildcard patterns
101+
102+
Wildcards match multiple fields with a single pattern. Use `*` to match any single path segment.
103+
104+
**Single wildcard:**
105+
106+
```json
107+
{
108+
"injectLocale": ["pages.*.locale"]
109+
}
110+
```
111+
112+
This matches:
113+
114+
```json
115+
{
116+
"pages": {
117+
"home": { "locale": "en" },
118+
"about": { "locale": "en" },
119+
"contact": { "locale": "en" }
120+
}
121+
}
122+
```
123+
124+
**Multiple wildcards:**
125+
126+
```json
127+
{
128+
"injectLocale": ["sections.*.meta.locale"]
129+
}
130+
```
131+
132+
This matches nested structures where locale codes appear at a consistent depth.
133+
134+
### Forward slash notation
135+
136+
Patterns support forward slashes for keys that contain slashes in their names.
137+
138+
```json
139+
{
140+
"injectLocale": ["meta/a/lang", "meta/b/lang"]
141+
}
142+
```
143+
144+
This matches:
145+
146+
```json
147+
{
148+
"meta/a/lang": "en",
149+
"meta/b/lang": "en"
150+
}
151+
```
152+
153+
## How inject locale works
154+
155+
Understanding the mechanism helps you predict behavior and troubleshoot issues.
156+
157+
### Reading phase
158+
159+
When Lingo reads a source file, it scans for fields matching your patterns. For each match, it checks whether the field's value equals the current locale code. If the value matches, Lingo removes the field temporarily. If the value does not match, Lingo leaves the field unchanged.
160+
161+
**Example:**
162+
163+
Source file `locales/en.json`:
164+
165+
```json
166+
{
167+
"locale": "en",
168+
"welcome": "Welcome",
169+
"meta": {
170+
"locale": "en"
171+
}
172+
}
173+
```
174+
175+
Configuration:
176+
177+
```json
178+
{
179+
"injectLocale": ["locale", "meta.locale"]
180+
}
181+
```
182+
183+
After reading, the internal representation excludes the locale fields:
184+
185+
```json
186+
{
187+
"welcome": "Welcome"
188+
}
189+
```
190+
191+
The removed fields are recorded so they can be re-inserted later.
192+
193+
### Writing phase
194+
195+
When Lingo writes a translated file, it re-inserts the fields that were removed during reading. Each field receives the locale code appropriate for the target file.
196+
197+
**Example:**
198+
199+
After translating to French, Lingo writes `locales/fr.json`:
200+
201+
```json
202+
{
203+
"locale": "fr",
204+
"welcome": "Bienvenue",
205+
"meta": {
206+
"locale": "fr"
207+
}
208+
}
209+
```
210+
211+
The locale fields now contain `"fr"` instead of `"en"`, matching the target locale.
212+
213+
## Conditional behavior
214+
215+
Inject locale only affects fields that meet specific conditions.
216+
217+
**A field is removed during reading if:**
218+
219+
1. The field matches a pattern in `injectLocale`
220+
2. The field's value exactly equals the current locale code
221+
222+
**A field is re-inserted during writing if:**
223+
224+
1. The field was removed during reading
225+
2. The field existed in the original source file
226+
227+
This conditional behavior prevents unintended modifications. If a field's value is not a locale code, Lingo leaves it unchanged. If a field did not exist in the source, Lingo does not add it to translations.
228+
229+
## Complete example
230+
231+
This example demonstrates inject locale with a multi-page application structure.
232+
233+
### Source file
234+
235+
File: `locales/en.json`
236+
237+
```json
238+
{
239+
"locale": "en",
240+
"pages": {
241+
"home": {
242+
"locale": "en",
243+
"title": "Home",
244+
"description": "Welcome to our website"
245+
},
246+
"about": {
247+
"locale": "en",
248+
"title": "About",
249+
"description": "Learn more about us"
250+
},
251+
"contact": {
252+
"locale": "fr",
253+
"title": "Contact",
254+
"description": "Get in touch"
255+
}
256+
}
257+
}
258+
```
259+
260+
### Configuration
261+
262+
```json
263+
{
264+
"version": 1.9,
265+
"locale": {
266+
"source": "en",
267+
"targets": ["fr", "de"]
268+
},
269+
"buckets": {
270+
"json": {
271+
"include": ["locales/[locale].json"],
272+
"injectLocale": ["locale", "pages.*.locale"]
273+
}
274+
}
275+
}
276+
```
277+
278+
### Translation result
279+
280+
File: `locales/fr.json`
281+
282+
```json
283+
{
284+
"locale": "fr",
285+
"pages": {
286+
"home": {
287+
"locale": "fr",
288+
"title": "Accueil",
289+
"description": "Bienvenue sur notre site"
290+
},
291+
"about": {
292+
"locale": "fr",
293+
"title": "À propos",
294+
"description": "En savoir plus sur nous"
295+
},
296+
"contact": {
297+
"locale": "fr",
298+
"title": "Contact",
299+
"description": "Contactez-nous"
300+
}
301+
}
302+
}
303+
```
304+
305+
Notice that:
306+
307+
- The top-level `locale` field changed from `"en"` to `"fr"`
308+
- The `pages.home.locale` field changed from `"en"` to `"fr"`
309+
- The `pages.about.locale` field changed from `"en"` to `"fr"`
310+
- The `pages.contact.locale` field remained `"fr"` because it did not match the source locale
311+
312+
## Common patterns
313+
314+
These patterns cover typical use cases.
315+
316+
**Application metadata:**
317+
318+
```json
319+
{
320+
"injectLocale": ["locale", "lang", "language"]
321+
}
322+
```
323+
324+
**CMS content:**
325+
326+
```json
327+
{
328+
"injectLocale": ["meta.locale", "content.lang"]
329+
}
330+
```
331+
332+
**Multi-page structures:**
333+
334+
```json
335+
{
336+
"injectLocale": ["*.locale", "pages.*.meta.lang"]
337+
}
338+
```
339+
340+
**Framework configurations:**
341+
342+
```json
343+
{
344+
"injectLocale": ["config.locale", "settings.language"]
345+
}
346+
```
347+
348+
## Relationship to locked keys
349+
350+
The `lockedKeys` feature serves a different purpose. Locked keys prevent specific fields from being translated at all. Inject locale, by contrast, removes fields temporarily but allows other fields in the same file to be translated.
351+
352+
Use `lockedKeys` when a field should never change. Use `injectLocale` when a field should automatically update to match the target locale.
353+
354+
## Troubleshooting
355+
356+
**Locale fields are being translated:**
357+
358+
Check that the field's value exactly matches the source locale code. Inject locale only removes fields when the value is a locale code. If the value is different, the field will be sent for translation.
359+
360+
**Locale fields are not appearing in translations:**
361+
362+
Verify that your patterns match the field paths in your files. Use dot notation for nested fields and ensure wildcard patterns align with your file structure.
363+
364+
**Some locale fields update but others do not:**
365+
366+
Inject locale only affects fields that matched the source locale during reading. If a field contained a different locale code in the source file, it will not be updated in translations.
367+
368+
## Technical details
369+
370+
Inject locale is implemented as a loader in the translation pipeline. The loader processes files at `src/cli/loaders/inject-locale.ts:6` and uses the minimatch library for pattern matching.
371+
372+
During the pull operation, the loader calls `_getKeysWithLocales` at `src/cli/loaders/inject-locale.ts:14` to identify matching fields and removes them using lodash's `omit` function. During the push operation, the loader re-inserts the removed fields at `src/cli/loaders/inject-locale.ts:30` using lodash's `set` function with the target locale.
373+
374+
The feature was introduced in configuration version 1.3 and enhanced in version 0.107.0 to support forward slash notation in patterns.

0 commit comments

Comments
 (0)