monorepo: [design flaw] config as code is wrong

Problem

The js config can’t be modified by apps.

  • users can’t add languages in the editor
  • lints can’t be changes by translators
  • the list goes on…

Proposal

Replace the JS config with a JSON config that can be modified by apps (similar to VSCode settings).

  • enables apps to be much more powerful
  • apps can work independently of developers (translator wants to add a plugin for example)
  • only importing plugins is what user config do anyways, nobody uses the power of code now that plugins are available
  • entails the requirement for #1140
{
  "referenceLanguageTag":"en",
  "languageTags":[
    "en",
    "de",
    "fr"
  ],
  "plugins":{
    "inlang.standardLintRules":{
      "module":"https://cdn.jsdelivr.net/npm/@inlang/plugin-standard-lint-rules@3/dist/index.js"
    },
    "inlang.plugin-json":{
      "module":"https://cdn.jsdelivr.net/npm/@inlang/plugin-json@3/dist/index.js",
      "options":{
        "pathPattern":"source-code/website/lang/{language}.json"
      }
    }
  },
  "lint":{
    "rules":{
      "inlang.missingMessage":"off"
    }
  }
}

Sub-issues

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 1
  • Comments: 17 (17 by maintainers)

Most upvoted comments

Please vote on JSON as the config format.

Pros

  • roundtrip capabilities
  • format with a native parser (in nearly every programming language) JSON.parse
  • “everyone” understands JSON compared to TOML for example
  • JSON just works (compared to YAML)

Cons

  • no native comments

@ivanhofer We will have the same formatting issues with json. So maybe use a library that works on an AST?

Too complicated. @felixhaeberle just worked with JSONC in VSCode. It’s horror.

Madame et Monsieur – hold on to the handrail, @NiklasBuchfink is sketching on a Post-It again 😄

(context: while in our bachelors, niklas often summarized/sketched good ideas on one single post-it while other people were trying to build up big sketches on the whiteboard 😅)

I agree with the point that inlang does not need a JS config file.

I took another look at the initial RFC and compared it to the RFC of pipeli18ne to see why we both came up with the “config as code” approach. For pipeli18ne it is beneficial because it is a more flexible system (pipelines), primarely designed for developers. But inlang uses “apps” to offer it’s functionality. Those apps will contain the complexity.

The reason why we did introduce “plugins” is to make the inlang config simpler. Now it is so simple, that we don’t need the config as code anymore 💪. Because the config needs to be parsed also inside a browser the config as code has also it’s limitations, because it can’t use standards like regular imports of relative files, which always made it odd to set one up ($env). So in my opinion a JS config without the full power of JS does not make that much sense.

Migrating to a json, or any other format (e.g. yaml) could fit. Just don’t use xml as a format!! 😅

If we choose json as a format, we should use JSON5 to support comments. Quote from @samuelstroschein: “Furthermore, JavaScript as config solves two common config file annoyances. First, comments are supported, and type annotations via JSDoc/TypeScript enable autocomplete and type safety.”

One key point in favor of js was the possibilty to offer typesafety (which fall apart due to the non-standard $env imports). This is also an option for json and yaml files, but only in a generic way (we can’t really type the dynamic plugins object). In the future we could use the IDE extension to show configuration issues inline. And for now we should make sure that each plugin checks if the passed config matches it’s expectations.

I have some details which we should consider for the refactoring:

  • languageTags can be defined in the inlang config, but also a plugin should be able to define them. The important thing should be, that once the app is initialized, that prop should be here
  • the thing that we currently call “plugin” sohuld be renamed to “message-plugin”. “lint-rules” are also “plugins”, but have their dedicated naming. I would add a new prop “messages” to the config to make it clear that this “plugin” is responsible to read/write messages. Question? Is it allowed to have multiple “messages” plugins? Could make sense as I have worked with apps where part of the translations were in a DB and some parts in .json files. Then each Message would also need a new prop to know which plugin is responsible. But this is probably a use case we can work on in the future.
  • combine lint plugin definition and lint configuration. “lint-plugins” should not be treated as plugins. They should have their own spot in the config to make it easier to configure them.
  • it should be encouraged to reference plugins (and lint-rules) by their identifier + version and not the url. “@inlang/plugin-json@3” is all we need to fetch the code from the jsdelivr CDN. If something is hosted somewhere else (private Company server), it still can be referenced via an url.

Here is an example for a config:

{
 "referenceLanguageTag": "en",
 "messages": {
   "https://cdn.jsdelivr.net/npm/@inlang/plugin-json@3/dist/index.js": {
       "pathPattern":"source-code/website/lang/{language}.json"
   }
 },
 "lint":{
   "inlang.standardLintRules@3": {
     "missingMessage":"off"
   }
 }
}

Additional considerations:

  • each plugin should define it’s version and the version of core it uses as a prop, which will make future migration easier because we can e.g. have some conditional logic inside core or an app that makes it possible to use older plugins for a few months, without requiring to coordinate everything.

Closing as “decided to have JSON as config format”

@ivanhofer If I remember correctly (I do not have experience working with json5 – please correct me if I’m wrong), it does not have built-in roundtrip support in the sense that it is not directly designed to preserve all aspects of the original JSON5 data structure during parsing and serialization.

  • In the future, we should be able to change settings without editing code. There should be an option in the future to distinguish between private and project settings (user configs / app internal settings via localstorage / …)
  • JSON is easier to understand for devs
  • Typesafty is easier

Agree with the proposal 👍