Paraglide JS CLI compiles an inlang translation project into JavaScript message functions that applications can import, type-check and bundle. It is useful for teams that want a compiler-first localization workflow rather than depending entirely on runtime string-key lookups, but it still requires correct language data and careful locale routing.
Developers searching for `@inlang/paraglide-js compile`, Paraglide message generation, typed translation imports, `project.inlang` configuration or a standalone server internationalization build can follow this guide to understand the production path from source messages to the browser. It covers practical compilation, developer checks and what cannot be inferred from a successful build.
In brief: configure supported locales, compile messages to a controlled output directory, import generated functions through a stable interface, and test both message meaning and runtime locale selection. Include plural variants, interpolation, Unicode, server-side rendering, translated metadata and deployment-specific QA before describing the application as multilingual.
- Current CLI pattern: npx @inlang/paraglide-js compile –project ./project.inlang –outdir ./src/paraglide –emit-ts-declarations
- Use –watch only for a development process that needs regeneration on file changes.
- Prefer documented bundler integrations when the application’s lifecycle benefits from them.
- Do not confuse tree-shaking unused messages with shipping a single locale per build.
An illustrative standalone compilation
The official command examples use an inlang project directory and an output directory for the generated modules. Run the exact commands for your installed release and verify that your application imports the resulting files. This demonstrates compilation only: a production server must still resolve locales for requests and the browser must render the correct message.
npx @inlang/paraglide-js compile --project ./project.inlang --outdir ./src/paraglide --emit-ts-declarations
npx @inlang/paraglide-js compile --project ./project.inlang --outdir ./src/paraglide --emit-ts-declarations --watch
npx @inlang/paraglide-js compile --help1. Why compile translations before runtime
Paraglide JS is a compiler-first internationalization approach. Rather than asking a browser to look up every message in a large runtime dictionary, it transforms a configured inlang project into importable message functions. This is a different architectural decision from simply loading JSON over the network.
The practical question is whether a component imports a stable message function and receives the language it expects. Trace one visible label from the source message through generated modules to the rendered application and keep a record of that path.
Compilation can reduce certain kinds of runtime lookup problems, but cannot decide whether a phrase is idiomatic, legally adequate or understandable for its audience.
Test this point with a deliberately small message fixture. Keep the source sentence, one target translation and the final rendered action together. A reviewer should be able to explain not only which file was generated, but what a user saw and whether they could complete the intended task.
2. Start with a supported inlang project
The project.inlang directory and its settings describe the languages and the translation-file integration. Paths and plugins matter because the compiler can only use the messages the configured project makes available.
Begin with a small source locale and one target locale, using the setup guide for the installed Paraglide release. Inspect the generated project configuration before editing patterns, adding translators or creating additional locale files.
A valid folder structure alone is not proof of coverage. Introduce a short test message, compile it and verify that the generated function resolves to the expected target phrase.
Use a controlled counterexample: change or remove a source message in a temporary branch, run the documented build and inspect what happens to imports and diagnostics. A check is useful only if its limitations are understood before an actual release defect occurs.
3. Treat init as a setup step
The CLI offers project initialization for supported environments, but a framework template may include routing or bundler conventions beyond the general compiler. Do not assume every new repository has the same middleware requirements.
Run the documented init procedure in a test branch and review added dependencies, settings and generated directories. In existing applications, compare the setup guide with your framework’s current integration instructions before replacing a working localization layer.
Keep the resulting changes under version control. The ability to reproduce setup on a clean checkout matters more than having a command finish with no error.
Keep a practical evidence bundle: installed package version, project configuration, source locale, target locale, generated output path and a browser screenshot. These items let another engineer reproduce the result without changing the meaning of an unrelated message.
4. Use the compile command deliberately
Standalone CLI compilation is useful when a project does not want a bundler plugin or when a CI pipeline needs explicit generated output. The official syntax accepts a project location and an output directory.
A representative command is npx @inlang/paraglide-js compile –project ./project.inlang –outdir ./src/paraglide. The exact installed version and flags should be checked with compile –help before changing production scripts.
Inspect generated files and application imports after compilation. A successful command can still be followed by a wrong import path or an application rendering in its fallback language.
A language-review decision should be separated from an engineering decision. The compiler can establish valid resource generation, while a qualified reviewer judges tense, politeness, instructions and terminology. Neither role can safely be inferred from the other’s green status.
5. Type declarations for editors
Generated declaration files can help an editor detect mistyped message names and parameters, especially where the application mixes JavaScript and TypeScript. They are a developer aid, not a translation dictionary.
The maintained CLI documentation shows –emit-ts-declarations for standalone builds. Use it when appropriate, compare declarations with actual exported functions and make sure the editor resolves the generated location.
A type check does not know whether ‘Cancel’ is a payment cancellation or a dialog dismissal. Keep language context in the source and in translator notes.
Compare normal and difficult examples, such as a short navigation label and a long warning with dynamic content. They place different demands on formatting, direction and layout. A sensible release suite covers both instead of celebrating only the simplest demonstration.
6. Watch mode and its boundaries
During development, watching translation changes can keep generated message functions in sync without repeated manual commands. It does not replace the need to run a deterministic production build.
Use the documented –watch option in development if it fits the workflow. For CI, compile in a clean, noninteractive step and avoid depending on a developer’s background watcher.
Deliberately change a target message and confirm the regenerated application reflects it. If it does not, identify whether watching, bundling, caching or the runtime locale selection is responsible.
Test this point with a deliberately small message fixture. Keep the source sentence, one target translation and the final rendered action together. A reviewer should be able to explain not only which file was generated, but what a user saw and whether they could complete the intended task.
7. Bundler plugin versus standalone CLI
The official guidance generally favors bundler plugins for automatic integration, while standalone CLI compilation suits pipelines or projects without that integration. The two approaches can target the same message source but have different lifecycle behavior.
Pick one authoritative generation path. Avoid running overlapping generators that overwrite each other’s output or leave stale modules. Write down which command must run before a production build.
Test a fresh clone and a clean build directory. A successful local hot reload may hide missing generation steps in deployment.
Use a controlled counterexample: change or remove a source message in a temporary branch, run the documented build and inspect what happens to imports and diagnostics. A check is useful only if its limitations are understood before an actual release defect occurs.
8. Static message imports
Static imports help bundlers reason about which generated message functions are used. Dynamic indexing through a message namespace can defeat some of those optimizations and make it harder to trace dependencies.
Use explicit imports and call sites where practical, such as a stable message function for a known button label. Keep a mapping from message identifiers to the actions they describe.
Measure the resulting bundle if performance is a goal, but do not promise a specific reduction without a comparable before-and-after build.
Keep a practical evidence bundle: installed package version, project configuration, source locale, target locale, generated output path and a browser screenshot. These items let another engineer reproduce the result without changing the meaning of an unrelated message.
9. Message naming
A message key should survive a wording improvement without pretending the English sentence is permanent. Names that reflect user intent are easier to maintain than arbitrary abbreviations.
Prefer identifiers associated with a feature and action, such as an account recovery confirmation, and avoid overloading one key for multiple meanings. When a key is renamed, update its generated references and every affected locale.
A typed identifier protects spelling and existence at compile time, not the meaning of the target text. Keep context notes accessible to translators.
A language-review decision should be separated from an engineering decision. The compiler can establish valid resource generation, while a qualified reviewer judges tense, politeness, instructions and terminology. Neither role can safely be inferred from the other’s green status.
10. Interpolation as typed data
Applications frequently insert a name, count, amount or date into a translated message. These values are a contract between the component and the message, and languages may need a different word order.
Define the variable explicitly in the message format and verify the generated function’s expected parameters. Test with names containing accents, long words and right-to-left text instead of only with John and Jane.
Confirm that a dynamic value is appropriately escaped for the output context. Compilation does not make arbitrary user-supplied markup safe.
Compare normal and difficult examples, such as a short navigation label and a long warning with dynamic content. They place different demands on formatting, direction and layout. A sensible release suite covers both instead of celebrating only the simplest demonstration.
11. Plural variants
English singular and plural examples do not capture every language’s grammar. A product saying ‘one file’ or ‘five files’ may require different forms and agreements in Arabic, Slavic languages or other locales.
Use the message format and plural mechanisms documented for the installed Paraglide release. Test representative counts and the natural noun phrase as a whole rather than translating just the suffix.
The correct selection rule and the correct sentence are separate requirements. Have target-language reviewers inspect actual rendered examples.
Test this point with a deliberately small message fixture. Keep the source sentence, one target translation and the final rendered action together. A reviewer should be able to explain not only which file was generated, but what a user saw and whether they could complete the intended task.
12. Select messages and variants
A message can depend on more than quantity: status, gender, role or product mode can change which words are appropriate. Variants should model a real distinction, not serve as a workaround for every design problem.
Keep a finite set of allowed states and document what each means. Pass predictable inputs, compile the catalogues and test every branch in at least the source and a target locale.
Where a variant expresses an important permission or payment state, obtain product approval for the source meaning before translation.
Use a controlled counterexample: change or remove a source message in a temporary branch, run the documented build and inspect what happens to imports and diagnostics. A check is useful only if its limitations are understood before an actual release defect occurs.
13. Formatting numbers and currency
Messages are only one layer of localization. A number or price may need locale-appropriate formatting, separators, currency symbols and rounding rules that plain string substitution does not supply.
Use the maintained runtime and formatting APIs documented for your version, or a suitable locale-aware formatting facility. Verify the output with real currency and decimal scenarios.
Do not change the numeric value to make a sentence look natural. The display format can vary while the economic quantity remains the same.
Keep a practical evidence bundle: installed package version, project configuration, source locale, target locale, generated output path and a browser screenshot. These items let another engineer reproduce the result without changing the meaning of an unrelated message.
14. Dates and time zones
A translated date caption can be misleading when the application formats it in the wrong locale or shifts the date boundary across time zones. Language selection and time-zone selection are related but distinct.
Test a timestamp near midnight and clarify whether the user sees local time, server time or an explicit zone. Keep the stored instant separate from the human-readable label.
A correct message function cannot repair a calendar date that was computed incorrectly before formatting.
A language-review decision should be separated from an engineering decision. The compiler can establish valid resource generation, while a qualified reviewer judges tense, politeness, instructions and terminology. Neither role can safely be inferred from the other’s green status.
15. Locales and region tags
Language codes may be broad or region-specific. English, English for Britain and English for the United States can differ in spelling and conventions while remaining mutually understandable.
Define supported locales and their fallback intent in project configuration and runtime behavior. Try a request for a locale that is not fully translated and check which messages the user actually sees.
Do not claim a regional translation exists simply because a more general language bundle can be displayed.
Compare normal and difficult examples, such as a short navigation label and a long warning with dynamic content. They place different demands on formatting, direction and layout. A sensible release suite covers both instead of celebrating only the simplest demonstration.
16. Locale detection on servers
A server must choose a locale for each request. A shared global language setting can cause one visitor’s language to leak into another visitor’s response in concurrent applications.
Use the framework’s documented request-scoped integration or middleware to resolve language from route, cookie or supported negotiation strategy. Test simultaneous requests for different locales.
The acceptance test is independence: two users requesting different languages should receive their own text, metadata and navigation without cross-contamination.
Test this point with a deliberately small message fixture. Keep the source sentence, one target translation and the final rendered action together. A reviewer should be able to explain not only which file was generated, but what a user saw and whether they could complete the intended task.
17. Standalone web servers
Paraglide provides examples for standalone servers including Express and other frameworks, but the surrounding application still owns request handling, redirects and output. Localization middleware is not a complete web architecture.
Follow the current standalone integration guide, compile before startup and examine how each request sets or obtains a locale. Keep source code, generated output and deployment paths consistent.
Test direct navigation, refresh and a request with no saved locale. One successful client-side switch is not enough for a multilingual site.
Use a controlled counterexample: change or remove a source message in a temporary branch, run the documented build and inspect what happens to imports and diagnostics. A check is useful only if its limitations are understood before an actual release defect occurs.
18. Localized routing
A page can display translated text yet have a URL, breadcrumb or menu that points readers back to another language. Route design is a separate product decision from message compilation.
Choose whether language lives in a path segment, domain or negotiated preference, and make navigation links preserve that choice. Check direct links, canonical URLs and locale alternates against the actual available pages.
Do not create search-engine alternate links for non-existent locale content. The machine-readable claim must match what visitors can read.
Keep a practical evidence bundle: installed package version, project configuration, source locale, target locale, generated output path and a browser screenshot. These items let another engineer reproduce the result without changing the meaning of an unrelated message.
19. SEO titles and metadata
Search engines often discover a locale through page titles, descriptions and structured navigation as well as the text on the page. These strings may be assembled outside ordinary UI components.
Identify which metadata uses message functions and which is produced by the framework. Translate only what has a real local-language page and validate the HTML emitted by the server.
A green message compilation report does not guarantee good indexability or accurate search snippets. Inspect the actual rendered document.
A language-review decision should be separated from an engineering decision. The compiler can establish valid resource generation, while a qualified reviewer judges tense, politeness, instructions and terminology. Neither role can safely be inferred from the other’s green status.
20. Client and server hydration
A server may render one language while a browser initially selects another. That disagreement can cause hydration warnings, visibly changing labels or confusing assistive technologies.
Make the initial locale decision consistent across server rendering and client startup. Test with a fresh browser, a stored locale preference and a direct link to a target-language page.
Observe the first paint as well as the settled screen. A correctly translated second frame may still deliver a poor first experience.
Compare normal and difficult examples, such as a short navigation label and a long warning with dynamic content. They place different demands on formatting, direction and layout. A sensible release suite covers both instead of celebrating only the simplest demonstration.
21. Output structures and sharding
The compiler can emit message modules in different layouts. The maintained docs describe grouping messages into shards for some build targets, which can reduce filesystem overhead in large projects.
Choose an output structure based on your bundler and repository size rather than copying an optimization from an unrelated framework. Document import conventions and rerun type checks if the output layout changes.
Measure build time and bundle behavior before and after. Avoid promising that every structure automatically loads only one locale.
Test this point with a deliberately small message fixture. Keep the source sentence, one target translation and the final rendered action together. A reviewer should be able to explain not only which file was generated, but what a user saw and whether they could complete the intended task.
22. Tree shaking claims
Static imports can let a bundler discard unused message functions, but the observed result depends on how code is imported and on the bundler’s configuration. Default output can still contain several active locale branches.
Compare a production build with a baseline and inspect the emitted chunks. Keep imports statically analyzable where possible and distinguish unused-message removal from per-locale builds.
Performance improvements should be presented as measured results for the specific application. Translation quality and accessibility must not be sacrificed for smaller assets.
Use a controlled counterexample: change or remove a source message in a temporary branch, run the documented build and inspect what happens to imports and diagnostics. A check is useful only if its limitations are understood before an actual release defect occurs.
23. Per-locale build options
Some Paraglide integrations support specialized client output for a particular locale. Such builds introduce additional deployment and routing responsibilities and are not appropriate for every framework.
Check the official compiler and bundler support matrix before enabling a per-locale option. Confirm how the server chooses the correct client graph and how a user changes language.
If unsupported, prefer the documented standard build. A partial optimization that serves the wrong locale is worse than a slightly larger correct bundle.
Keep a practical evidence bundle: installed package version, project configuration, source locale, target locale, generated output path and a browser screenshot. These items let another engineer reproduce the result without changing the meaning of an unrelated message.
24. Generated files and version control
Some teams commit generated message modules; others regenerate them in CI. Either choice can work if the steps are repeatable and ownership is clear.
Decide whether generated output is a reviewed repository artifact or a disposable build product. Use a clean build and check for unexpected diffs. Never manually translate inside generated JavaScript files.
The source of truth should remain the approved messages and project configuration. Editing output by hand creates changes that vanish on the next compile.
A language-review decision should be separated from an engineering decision. The compiler can establish valid resource generation, while a qualified reviewer judges tense, politeness, instructions and terminology. Neither role can safely be inferred from the other’s green status.
25. Monorepos and shared messages
A monorepo may have several applications using one set of messages or several independent locales. Shared resources can reduce duplication but also create accidental coupling across products.
Choose explicit ownership boundaries for each inlang project and generated output directory. Confirm that package builds do not overwrite one another and that a change reaches the intended consumer only.
Test one shared label and one app-specific label. Both should resolve correctly after a clean package install and build.
Compare normal and difficult examples, such as a short navigation label and a long warning with dynamic content. They place different demands on formatting, direction and layout. A sensible release suite covers both instead of celebrating only the simplest demonstration.
26. Translation editing and provenance
A text editor, external translation platform or repository pull request can produce message changes. Teams must retain enough context to decide whether those changes are trustworthy.
Record the source revision, intended locale, reviewer and reason for important wording changes. Avoid sending private customer text to external machine-translation services without permission.
A complete JSON file is not the same as a reviewed document. Preserve the distinction between proposed, reviewed and released translations.
Test this point with a deliberately small message fixture. Keep the source sentence, one target translation and the final rendered action together. A reviewer should be able to explain not only which file was generated, but what a user saw and whether they could complete the intended task.
27. Pseudolocalization tests
English tends to hide width and character-coverage defects. Expanding strings or inserting non-Latin test characters early can expose clipping, hard-coded widths and fonts that do not cover target scripts.
Use reversible synthetic test strings in a development environment and inspect navigation, error dialogs and dense mobile layouts. Test actual translations before release, not only placeholders.
The goal is layout resilience, not an artificial linguistic score. A user must be able to read the full instruction and reach the right action.
Use a controlled counterexample: change or remove a source message in a temporary branch, run the documented build and inspect what happens to imports and diagnostics. A check is useful only if its limitations are understood before an actual release defect occurs.
28. Right-to-left and Unicode
Script coverage, bidirectional punctuation and input direction belong to runtime UI behavior. Message compilation does not automatically mirror every control or isolate embedded technical identifiers.
Test Arabic or Hebrew content where relevant, including numbers, email addresses and mixed-script identifiers. Verify focus order, screen readers and punctuation in the actual layout.
Keep technical tokens outside prose where appropriate; their direction and semantic role should not change unexpectedly.
Keep a practical evidence bundle: installed package version, project configuration, source locale, target locale, generated output path and a browser screenshot. These items let another engineer reproduce the result without changing the meaning of an unrelated message.
29. Failure diagnosis in CI
A failed compile could be caused by project settings, missing files, malformed messages or mismatched dependency versions. Each cause deserves a different remedy.
Run the compiler in a clean container using pinned dependencies and save concise logs. If errors occur, identify the exact file and message before changing global configuration.
Do not disable validation because a vendor has not finished translating. Separate incomplete content from malformed source syntax so the correct owner can act.
A language-review decision should be separated from an engineering decision. The compiler can establish valid resource generation, while a qualified reviewer judges tense, politeness, instructions and terminology. Neither role can safely be inferred from the other’s green status.
30. Release sign-off
The multilingual release needs more than a successful generated directory. People need to understand pricing, permissions, errors, instructions and navigation in the language the product promises.
Verify compilation, type checks, direct locale routing, server-client consistency, representative plurals, long strings and real user tasks. Ask language reviewers to sign off on high-impact copy.
State precisely which locale and device combinations were tested. A build that contains strings for twenty languages does not automatically constitute twenty fully verified local-language experiences.
Compare normal and difficult examples, such as a short navigation label and a long warning with dynamic content. They place different demands on formatting, direction and layout. A sensible release suite covers both instead of celebrating only the simplest demonstration.
Worked example: localized ticket-confirmation pages
Imagine a multilingual events website running on a small server. Its English confirmation says a ticket remains provisional until payment is verified. A Spanish message file has an older sentence implying immediate acceptance, and a German number-formatting component displays a decimal separator inconsistently. The server also selects one global locale variable for every incoming request, so two visitors sometimes receive mixed-language text. The compiler could produce fully valid functions while all three defects remain.
Begin with the approved message meaning and an inlang project that exposes the intended locales. Compile in a clean build, import message functions statically and run type checks. Ask qualified readers to review the revised Spanish sentence. Exercise a formatted payment amount and determine whether the user’s locale or a separate currency rule controls it. Test two simultaneous language requests through the actual server adapter, verify the first HTML response and compare the client’s initial render. Finish with a mobile-width check and a screen-reader pass, then record the exact build and review status.
This rehearsal demonstrates the right scale of a localization claim. A generated JavaScript module is an engineering deliverable. A safe, understandable ticket confirmation is a product outcome that depends on message meaning, transaction status, formatting, routing and accessible UI behavior.
Frequently asked questions
Is Paraglide JS the same as i18next?
No. Both support internationalized interfaces, but Paraglide emphasizes compiled message functions and static imports. The surrounding routing, server and content-review tasks still require design decisions.
Does compilation translate English automatically?
No. Compilation turns existing message resources into executable output. It is not a substitute for qualified target-language writing and review.
Why would I use the CLI instead of a plugin?
The CLI suits explicit CI steps and projects without a supported bundler integration. Plugins can integrate regeneration into the normal development build. Choose one reproducible workflow.
What are the important CLI flags?
The maintained documentation demonstrates –project, –outdir, –emit-ts-declarations and –watch for compilation. Run –help on your installed version for the complete current option set.
Can generated functions still display wrong text?
Yes. A message can be valid and typed while semantically wrong, stale or inappropriate for a region. Review source meaning and target copy in the actual user flow.
What is the risk with a global server locale?
Concurrent requests may accidentally share a language if mutable state is not isolated. Use the documented request-scoped integration and test simultaneous visitors in different locales.
Why did my bundle not get smaller?
Static imports help bundlers identify unused functions, but results depend on imports and build configuration. Default output need not remove every inactive locale; measure an actual production build.
Does Paraglide solve multilingual SEO?
Not by itself. The application still has to provide localized URLs or page selection, metadata, navigation and correct server HTML. Confirm that search engines receive the language they are promised.
Should generated modules be edited directly?
No. Edit the source messages or project configuration and regenerate. Direct changes to generated output are lost on the next compiler run.
What constitutes adequate QA?
A repeatable build plus checks for interpolation, variants, locale switching, first paint, screen readers, mobile widths, right-to-left behavior and the language accuracy of important actions.
Documentation and further reading
The maintained Paraglide JS compiling-messages guide documents the compiler, CLI options and bundler choices, while the standalone server guide shows how a framework can use the generated runtime. Read the Paraglide introduction for output and tree-shaking concepts. The best next step is to test one typed message and one target-language server request from a clean build.