Code Monkey home page Code Monkey logo

inlang-message-sdk's People

Contributors

samuelstroschein avatar

Watchers

 avatar  avatar

inlang-message-sdk's Issues

Remove Solid from in-memory core message store

Context

Messages are currently stored in a solidjs reactive map which consumes excessive resources and does not scale well.

Replacing the internal solidjs reactive map for lint-reports successfully showed that this approach makes sense, as long as there is another notification mechanism for apps to react to changes.

Proposal

  • replace the internal reactiveMap with a vanilla js Map
  • trigger message update events independently when updates are handled (see loadProject.ts)
  • [tbd] Find a way to use the solidAdapter to make messages which are in-view reactive at the app-level.

Message-Query sometimes returns `undefined` instead of a message array

Context/Problem

project.query.message.getAll() sometimes returns undefined instead of a message array. This isn't reflected in the types.

The most likely cause is that the messages get queried before they are properly loaded & thus the query returns an uninitialized value.

This caused PARJS-57

Proposal

Either block until the messages are fully loaded before responding to the query, or return an empty array.

Design for human IDs and aliases

MESDK-59

OG issue & discussion: opral/monorepo#1892

The current experimental implementation of aliases is incomplete
Only the default alias is supported for plugin message IDs, and uniqueness is assumed.

Next steps

  • New message creation with auto-generated human id (no alias)
  • Improve Sherlock and Fink messages UI (e.g. "@" for aliases feels rough)
  • Improve tooling to connect messages wtih context / code
  • (?) additional alias types e.g. for mobile frameworks

Additional TODOs migrated from opral/monorepo#2346

plugin API where is a message used in source code for "unused message", "hardcoded text", etc. lint rules

Discussed in opral/monorepo#2126

Originally posted by samuelstroschein January 26, 2024

Problem

Several problems that relate to code can not be linted at the moment. For example:

  1. Is this message used? opral/monorepo#1961
  2. Does code include hardcoded text that needs to be extracted?
  3. opral/monorepo#2253

Proposal

Introduce an API for plugins to report where a message is used in source code.

The information where a message is used in source code can be used for several features:

  • decorators in @opral/inlang-ide-extension
  • a lint rule that detects unused messages
  • providing context in @opral/inlang-fink and other apps where a message is used

Thinks to consider

  • performance/caching of parsing source code (querying @opral/lix for changes of a file seems to be a quick win and good requirement for lix repo.fs.file("some-file").lastChange())
  • how can the API take as much work from plugin authors as possible e.g. in regards to caching & handling performance

Design for sdk core with non-reactive internal implementation + separate reactive api

Context/Problem

The current sdk implementation does not scale well. Reactive solid.js effects for messages and lint reports consume excessive CPU and memory resources as the number of messages grows. (see MESDK-29 and loom)

Proposal

  • Remove solid.js from the sdk core
  • core should offer a CRUD api for projects, messages + watcher api for events
  • offer a separate reactive api for building UIs.

SDK reactive API

from https://app.excalidraw.com/s/1RmnkzJA3Ph/27CVKAmMGKx

Weak error message when module in project settings fails typecheck

Context

E.g. The type declaration requires that modules URLs end in `.js`, but the error message when this is not the case, is unclear:

ProjectSettingsInvalidError: The project settings are invalid:

"/modules/0":

Expected all values to match
    at parseSettings (file:///Users/jldec/opral/monorepo/inlang/source-code/cli/dist/main.js:88702:13)
    at loadSettings (file:///Users/jldec/opral/monorepo/inlang/source-code/cli/dist/main.js:88695:10)

Proposal

Either improve the error, or remove the check if the error can't easily be improved
In this case, most bad urls will be caught by a module load error or another runtime error.

On-demand debug logging

Partial support for logging was implemented with the debug package e.g. in sdk/load-test.

  • make it work in browsers
  • extend support to other parts of the sdk using the sdk:module convention e.g. sdk:lintReports

sdk persistence: migration requirements

Context

sdk-persistence means that we can improve how the inlang sdk handles upgrades as we add features.

There is currently no migration mechanism for plugins. This means that users can (and do) get stuck on outdated plugins.

(correction April 23. The inlang message format plugin does have a migration capability for v1.x -> v2.x, documented in the changelog.)

Proposal

  1. Existing projects using plugins should be able to migrate to sdk persistence
    • Initally this can be a one-time, user-initiated process, e.g. triggered by the inlang CLI
    • Once stable, we should nudge users and offer to do this also from other apps
  2. The sdk should detect internal persisted format changes, and auto-migrate the sdk message store, without user intervention.
    • Some backward and forward sdk <-> file-format compatiblity is needed (details tbd)
    • Ensure all-or-nothing (atomic) migrations, and avoid file corruption.

get rid of versioned interface packages

Context

We define interfaces of the inlang sdk in dedicated packages. The idea was to decrease the impact of breaking changes of interfaces on the ecosystem. However:

  • plugins and lint rules import the sdk regardless of dedicated interface packages
  • more complex codebase
  • iteration speed slightly impacted see discussions like opral/monorepo#2700 (comment)

Proposal

Remove the versioned interfaces and put them in the SDK.

Video

https://www.loom.com/share/ca91189f093940c38ae0f2927725b06c?sid=93b4ddf6-ce84-4581-91f3-97987224652d

feat: settings schema in installedPlugin & installedMessagelintRule

I want to build the settings ui component based on the schema I get from the installed lint rules and plugins. The installed API only gives me access to id displayName description module.

Porposal:

  • Add settingsSchema to types:
export type InstalledPlugin = {
	id: Plugin["id"]
	displayName: Plugin["displayName"]
	description: Plugin["description"]
	/**
	 * The module which the plugin is installed from.
	 */
	module: string
	// disabled: boolean
+	settingsSchema: Plugin["settingsSchema"]
}

Same for message lint rule...

  • Add settingsSchema to InstalledPlugin & InstalledMessageLintRule:
        const installedPlugins = () => {
			if (!resolvedModules()) return []
			return resolvedModules()!.plugins.map((plugin) => ({
				id: plugin.id,
				displayName: plugin.displayName,
				description: plugin.description,
				module:
					resolvedModules()?.meta.find((m) => m.id.includes(plugin.id))?.module ??
					"Unknown module. You stumbled on a bug in inlang's source code. Please open an issue.",
+                settingsSchema: plugin.settingsSchema,
			})) satisfies Array<InstalledPlugin>
		}

Same for message lint rule...

It seems like an easy PR. @jurgen.leschner, let me know if I should open a PR to add this.

requirements lint rule per message/ per variant configuration

Problem

Lint rules are all or nothing. There is no way to ignore a warning coming from a lint rule just for a specific message.

This is especially annoying with the "duplicate pattern" lint rule which has a lot of false positives.

This has been a common complaint

Proposal

Some way to ignore lint warnings for specific messages.

This would likely require annotating messages with metadata.

cc @felix.haeberle

`pathpattern` cannot safely reference paths inside a project dir

MESDK-70

Context

https://github.com/opral/monorepo/pull/2590/files#discussion_r1567809135

"pathPattern": "./messages/{languageTag}.json", results in a tree like this:

.
├── messages
│   ├── de.json
│   └── en.json
├── project.inlang
│   └── settings.json

That puts the files in a peer directory called messages, not inside the project directory (i think this is from the time when project settings were just a json file.)

Proposal

We'll need to define a new way to specify paths inside the project, without assuming a specific project {name}.inlang in the path

SDK Message storage with support for full inlang message structure

MESDK-64

Context

There is currently no storage plugin which supports the full inlang Message structure.

This is required in order to unblock features like plurals and gender e.g. in paraglide.

Proposal

  • use the existing plugin API for loadMessages and saveMessages (no rewrite of loadProject)
  • store under project directory {name}.inlang/messages/…
  • enable with experimental persistence feature flag in project settings
  • NOTE: Non-human-editable

Requirements for message persistency

Context

This is a discussion issue for sdk persistency project requirements.

Why do we need persistence?

Inlang projects should provide built-in persistence instead of relying on developers to create text files with formats which may not support globalization needs.

Our goals with this work

  1. To simplify the inlang getting-started experience.
    Users create new inlang projects in 1 click => A project has built-in message storage.
  2. To support high-demand features like plurals, gender etc.
    Inlang projects store message variants, match patterns etc.
  3. To offer a smooth transition from directly editing messages in text files,
    to editing messages via a UI like Fink or Sherlock.
  4. To enable change-driven workflows e.g. across translators, developers, and designers.
    This means (a) mapping persisted message state changes to repo diffs/merges/commits, and (b) persisting repo workflow state like reviews and approvals alongside the persisted messages.
  5. To enable high quality, context aware, AI-assisted globalization.

Timeline considerations

In the short term, feature coverage (plurals, gender etc.) and human editability are most important. This speaks for shipping MVP persistence together with editor support ASAP.

Expose project `name` property

Context

This discussion came up while using the name of an inlang project in Sherlock. It would be great to have a project property called name which is the name of the inlang project.

Proposal

The name of the inlang project is most likely just the directory (file) name of the inlang project itself such as project.inlang, backend.inlang or happy-elephant.inlang


----

@samuel.stroschein said in SHERL-22:

EDIT: Is there a way to get the project name from the SDK API? Or can we only get it by reading the file path?

Only the file path name.

Suggestion: Pink message sdk team if adding project.name makes sense.

remove `tryCatch` stuff from inlang message sdk

Proposal

Remove the tryCatch stuff from message SDK in favor of standard JS.

Value of tryCatch is close to 0

@samuel.stroschein said in LIX-59:

EDIT: never mind. the value of tryCatch is close to 0.

@jldec what is your issue with the utility function tryCatch()? The function doesn't impact API design.

const file = await tryCatch(() => repo.fs.readFile())

if (file.error){
  // do something
}

const parsed = tryCatch(() => JSON.parse(file.value))

if (parsed.error){
  // do something
}

try {

  const file = await repo.fs.readFile()
  const parsed = JSON.parse(file)

} catch (e){
  if (e instanceof FileError){
    //
  } else if (e instanceof JSONError){
    //
  }
}

Requirements for gender and plurals

Context

Users are asking for inlang to support messages with variant for gender and plurals.

Proposal

Introduce new types which are aligned with ICU Message Format 2 messages and a new message bundle type to collect messages translated for different locales.

Requirements for module caching

Context

While pulling plugin modules e.g. for lint reports from a cdn is useful in environments which don't have a package manager (e.g. in browsers), the current behavior is surprising in other environments where installed packages are supported (e.g. in locally installed npm projects or in a vs code extension)

Please use this issue to report requirements.

  • performance: network requests are expensive e.g. on each paraglide compile
  • offline usage: could be mitigated by preloading and caching
  • security checks: would be easier with a trusted/enterprise package registry
  • plugin user DX: configuring and knowing which plugin is going to run should be simple
  • plugin developer DX: how to dev-test-build-ship new plugins and plugin-updates should be straightforward
  • reliability: depending on a 3rd party cdn which is not typically used for app hosting, adds operational risk
  • observability: it should be possible to trace plugin calls to debug when something is not right

lint rule: "a message should only be used once"

Discussed in opral/monorepo#2253

Originally posted by samuelstroschein February 18, 2024

Problem

Referencing the same message in multiple places leads to a broken message.

No guarantee exists that a message with the content like "learn more" won't be changed by someone to "learn more about unlimited inboxes". If the message is rendering all "learn more" references, the example website below will break at 2 and 3.

CleanShot 2024-02-18 at 14 08 36@2x

CleanShot 2024-02-18 at 14 08 36@2x

Proposal

A lint rule that detects if a message id is used multiple times in source code.

// unlimited inboxes
<p>{m.elephant_big_tree()}</p>

// manage team members
// 💥 error m.elephant is used multiple times
<p>{m.elephant_big_tree()}</p>

// spam report
// 💥 error m.elephant is used multiple times
<p>{m.blue_box({ title: m.elephant_big_tree() })}</p>

(Creating new messages is cheaper than trying to manage shared messages.)

Additional information

Report loading-errors from Plugins

Currently if a loading-error happens in a Plugin during message loading, perhaps due to a syntax error, it's quietly ignored. We should add a way to report loading issues from plugins so we can inform developers why loading is not working

sdk api for MessageBundle with variants

Context

The current MessageQueryApi operates on Message objects.

export type MessageQueryApi = {
	create: (args: { data: Message }) => boolean
	get: ((args: { where: { id: Message["id"] } }) => Readonly<Message>) & {
		subscribe: (
			args: { where: { id: Message["id"] } },
			callback: (message: Message) => void
		) => void
	}
	// use getByDefaultAlias() to resolve a message from its alias, not subscribable
	getByDefaultAlias: ((alias: Message["alias"]["default"]) => Readonly<Message>) & {
		subscribe: (alias: Message["alias"]["default"], callback: (message: Message) => void) => void
	}
	includedMessageIds: Subscribable<Message["id"][]>
	/*
	 * getAll is deprecated do not use it
	 */
	getAll: Subscribable<Readonly<Message[]>>
	update: (args: { where: { id: Message["id"] }; data: Partial<Message> }) => boolean
	upsert: (args: { where: { id: Message["id"] }; data: Message }) => void
	delete: (args: { where: { id: Message["id"] } }) => boolean
}

☝️ is exposed as project.query.messages in the InlangProject api

export type InlangProject = {
//  ....
	query: {
		messages: MessageQueryApi
		messageLintReports: MessageLintReportsQueryApi
	}
}

Proposal

From MESDK-77

after introducing UUIDs for variants / we will have to expose a project.query.variant.* next to project.query.messageBundle.* and project.query.message.*.

The comment above suggests a new MessageBundleQueryApi for apps to operate directly on the MessageBundle structure.

@samuel.stroschein @martin.lysk1
Given our experience with MessageQueryApi, do you think this proposal the right approach to use at this time?

unused messages lint rule

Discussed in opral/monorepo#1961

Originally posted by samuelstroschein January 2, 2024

Context

Over time messages became stale and are not used in source code anymore. No mechanism exists at the moment that "lints" unused messages that can safely be deleted. The result is an evergrowing amount of messages that translators are supposed to translate even though some or many messages aren't used.

Proposal

Introduce an "unused message" lint rule.

The lint rule parses the source code and searches for message references (similar/identical to the ide extensions message reference matchers)

Requirements

opral/monorepo#2126

Updated project settings should reload messages

MESDK-71

Context

Any modification of project settings should trigger a reload of messages e.g. to pick up new languages.

e.g. https://discord.com/channels/897438559458430986/1070750156644962434/1229849444728442964

Proposal

Doing this internally, at the sdk level, should allow sherlock users to edit project settings directly, and see the results without reloading manually.

NOTE: guard against a new message file overwriting an existing file which existed before the language was added to the project.

related to FINK-27 (opral/inlang-fink#17)

inlang/rpc:test is failing because of google translate issue:

Context

 ❯ src/functions/machineTranslateMessage.test.ts  (5 tests | 1 failed | 1 skipped) 805ms
   ❯ src/functions/machineTranslateMessage.test.ts > should not return escaped quotation marks
     → expected { id: 'mockMessage', alias: {}, …(2) } to deeply equal { id: 'mockMessage', alias: {}, …(2) }

⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯

 FAIL  src/functions/machineTranslateMessage.test.ts > should not return escaped quotation marks
AssertionError: expected { id: 'mockMessage', alias: {}, …(2) } to deeply equal { id: 'mockMessage', alias: {}, …(2) }

- Expected
+ Received

  Object {
    "alias": Object {},
    "id": "mockMessage",
    "selectors": Array [],
    "variants": Array [
      Object {
        "languageTag": "en",
        "match": Array [],
        "pattern": Array [
          Object {
            "type": "Text",
            "value": "'",
          },
          Object {
            "name": "id",
            "type": "VariableReference",
          },
          Object {
            "type": "Text",
            "value": "' added a new todo",
          },
        ],
      },
      Object {
        "languageTag": "de",
        "match": Array [],
        "pattern": Array [
          Object {
            "type": "Text",
            "value": "' ",
          },
          Object {
            "name": "id",
            "type": "VariableReference",
          },
          Object {
            "type": "Text",
-           "value": " ' hat eine neue Aufgabe hinzugefügt",
+           "value": " ' hat ein neues To-Do hinzugefügt",
          },
        ],
      },
    ],
  }

Proposal

fix it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.