unsplash / intlc Goto Github PK
View Code? Open in Web Editor NEWCompile ICU messages into code. Supports TypeScript and JSX. No runtime.
License: MIT License
Compile ICU messages into code. Supports TypeScript and JSX. No runtime.
License: MIT License
Output is unaffected at runtime as the duplicate branches are never reached in the switch statement, but ideally this'd be validated by the tool.
At the moment the parser parses plaintext as single characters and "reconciles" them later wherever we've come into contact with them. This is errorprone and untidy.
I've had this challenge before but for some reason the solution escapes me. Documenting it here in case anyone fancies cracking it! ๐
Example of the syntax: https://lingui.js.org/ref/message-format.html
{count, plural, offset:1
=0 {Nobody read this message}
=1 {Only you read this message}
one {You and # friend read this message}
other {You and # friends read this message}
At the moment you can specify an output "backend", but you might want multiple.
If/when we support multiple filetypes (we don't/wouldn't really yet as .ts
is subsumed by .tsx
) we can output multiple sibling files, but what about distinct backends for the same filetype?
Say, given "backends": ["ts", "tsx"]
, what should the output be? Because at present the export names would conflict.
At the moment everything is inlined.
Not entirely convinced it's well-behaved at present. ๐
Context: #39
"one" etc
And check in CI.
Should this be supported?
What should we do when we detect an unescaped hash outside of a plural?
It might be a good idea to use snapshot testing to test the TS output. Something like https://hackage.haskell.org/package/hspec-golden-0.2.0.0/docs/Test-Hspec-Golden.html โ I've given it a shot and it was easy to setup for a basic configuration. 922106f
Perhaps we could also take it a notch further and write a specific golden
config to output .ts
files and test them against the TS compiler or something to verify they are type safe? Perhaps prettify them as well somehow.
Context: #39
Context: #32 (comment)
Currently unsupported. Is it supported in other implementations? Should it be?
Keep ReactElement
. Currently blocked by web. Context: #32 (comment)
Test, lint, etc.
Context for translators: https://crewlabs.slack.com/archives/C0STWEZ2B/p1642186732014800?thread_ts=1642181054.008000&cid=C0STWEZ2B
Parse and probably discard.
Like #13.
This applies to both string and number unions as produced by select
and plural
respectively.
When the same input is referenced twice, one for a union type and one potentially not, we produce different type-level output based upon the order. This happens because we check for type compatibility, but don't actually consider which type or subset of these types to preserve. For example, given {n, number} {n, plural, =1 {x}}
we'll set the input to number
, but the only safe input is actually the literal 1
. If the interpolations are reversed we'll set the input to 1
, but this still may not be safe if there are other interpolations referencing n
later.
Additionally, it is possible for two unions to be incompatible if there are no overlapping members. An example is 1 | 2
and 3 | 4
for which there's no possible reconciliation. When two unions differ but there is at least one overlapping member, for example with 1 | 2
and 1 | 2 | 3
, we should narrow the input to 1 | 2
- the overlapping members - to ensure that both matches can succeed.
For TypeScript, one cheap way to solve this may be to offload this entirely to the compiler via intersection operators. (1 | 2) & (1 | 2 | 3)
resolves to 1 | 2
, and zooming further out string & number
resolves to never
. This could potentially simplify the codebase by removing typechecking in intlc entirely.
At the moment, mostly randomly, we tolerate empty braces and interpolations with bad types, but not empty or otherwise faulty tags. We should decide upon a uniform approach, considering flexibility and (ease of checking) correctness. Escaping (#11) may be relevant here.
e.g. if the same number is used twice we'll compile two instantiations of Intl.NumberFormat
. The compiler knows enough to potentially open a function body and declare a variable.
And then ensure they're not duplicates after any adjustments or made. Or filter out and potentially error on invalid keys. This should probably differ per-backend, or we could keep it very safe with alphanumerics.
It's all on a single line at the moment. We'll probably run Prettier against it in web, but ideally the output would be more legible out of the box.
It's a bit unnecessary and most of the time this will fail because it's looking for a transpiled file in the dist/
we may not have
Something, of some type, somehow - for example an additional function argument. Currently hardcoding en-US and otherwise not formatting strings and numbers.
Reduces character count and removes variable shadowing when they're nested.
It's currently very strict (easiest/cheapest/laziest implementation path). Fairly easily changed where we want flexibility.
Minimal repro: {n, selectordinal, one {x} other {y}}
"ts" output:
export const f = (x: { n: number }) => string = x => `${(() => { switch (x.n) { case 'one': return `x`; default: return `y`; } })()}`
Even more important now with flattening. This might mean moving away from Map
(and its Ord
constraint on its keys).
I kind of fell into alphabetical ordering as it was the easiest to implement, but probably fair to consider it a bug.
Examples:
push tag v0.2.1
-> bump @unsplash/[email protected]
push tag v0.3.0
-> bump @unsplash/[email protected]
I'm not sure what is the best way for doing that. We could add it to the CI but then we'd have to commit the package.json version change back into this repo ๐ค
Needs ReactElement
imported, and whatever best practices are now for bringing "React" and JSX sugar into scope. Let's not worry for now about other libraries/pragmas, that's tracked here: #33
We don't want to import this if we haven't used the "tsx" backend.
Going potentially further than this it's possible to use the aforementioned backend but still not require the imports, for example:
{
"x": {
"message": "y",
"backend": "tsx"
}
}
export const x: string = 'y'
A cheap and dirty way to do this would be to search the output string for ReactElement
. A better way would be to use the AST to know with confidence whether or not this has happened. One way to know is, in the JavaScript compiler, if we've ever unwrapped a Lambda
with a JSX
InterpStrat
- I think the dynamism of a lambda directly correlates to needing the import. Alternatively it may be cleaner to figure this out via the ICU Dataset
as then the logic can be a single, simple predicate function that exists outside of the complexity of the compiler.
Rather than dumping them all in "end to end".
Output return types in TS(X) are currently left to be inferred.
At the moment, for both plural
and selectordinal
, we allow "exact" (=0
) and "rule" (zero
) cases to be ordered in absolutely any way, and enforce that the wildcard (other
), if any, comes at the end. This is arbitrary and can be changed to be more or less strict.
Some locales may legitimately not need a variable that others do, for example in the case of gender. When this happens, if there are no other interpolations, we're going to output incompatible types across locales:
export const en: (x: { gender: 'male' | 'female' }) => string = x => etc
export const es: string = etc
Functions and strings can't unionise (no such value), however functions/objects with omitted properties can. Specifically:
type Current
= string
| ((x: { gender: 'male' | 'female' }) => string)
// TypeScript will insist upon providing a full `x`
type Proposed
= (() => string)
| ((x: { gender: 'male' | 'female' }) => string)
Context: #39
Worth exploring ways to simplify and condense it.
Since #38 we build a linux binary upon release. Should we also consider building one that'd work on mac os? Or should we expect mac os users to build it manually by pulling down the repo?
How will the locale be supplied or inferred?
And then update the README. (It's going to be out of date as of #39.)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.