Contents
Nobody porting a module from Python to JavaScript wants to hand-rewrite for i in range(n). The parts that block a port are rarely the interesting ones — they are the loops, the string formatting, the list appends, the True/False constants that a mechanical rewriter could handle in one pass. Full transpilers that guarantee semantic equivalence are genuinely hard; a static rewriter that covers the boring majority is not.
The Language Transpiler is a single client-side Astro page that does exactly that. Paste Python and get JavaScript; switch the direction and paste JavaScript to get Python. There is no backend, no language model, and no network call — every rewrite happens in your browser and the code never leaves the page.
What actually gets translated
The tool ships a fixed rule table, not a general compiler. In the Python-to-JavaScript direction it converts def definitions to function declarations, turns indentation into braces, and rewrites if / elif / else into if / else if / else. Loops map as you would expect: for i in range(n) becomes a C-style for loop over Python’s range and for x in xs becomes for...of. Builtins and constants follow — print(x) to console.log(x), True/False/None to true/false/null, and/or/not to &&/||/!, len(x) to x.length, and x.append(y) to x.push(y).
The JavaScript-to-Python direction mirrors the same table: brace blocks become indentation, console.log becomes print, === becomes ==, push becomes append, and the trailing semicolons come off.
How the heuristic works
The engine is line-oriented and stateful, not a parser. It walks the source one line at a time, tracks the current indentation depth in a stack, and applies a small set of ordered pattern rewriters to each line. For Python input, a deeper indent opens a brace block on the line above and a shallower one emits the closing braces; for JavaScript input the same stack runs in reverse, emitting a colon and increasing the indent where a brace opened. Because the transform is a deterministic function of the input, the same paste always produces the same output — you can diff two runs and get nothing.
This is the honest tradeoff. A real transpiler builds an abstract syntax tree, resolves names, and refuses to emit code it cannot prove equivalent. This tool does not. It is a rewrite table with a block-scope stack, and it is fast, inspectable, and has no dependencies.
What it deliberately leaves alone
Anything outside the documented subset stays byte-for-byte unchanged, and the tool flags it. Classes, async/await, decorators, lambdas, list comprehensions, object destructuring, switch statements, and spread syntax are all beyond the rule table. When a line contains one of these, the transpiler keeps the original text and adds an entry to the annotations panel with the line number and a one-line note explaining why it was skipped.
That behavior is the point. A silent mistranslation is far worse than a visibly skipped line, so the tool chooses visibility: everything it could not confidently rewrite is listed for you to handle by hand.
Limitations worth stating plainly
The rewriter is regex- and indentation-based, so it has no idea what is a string and what is code. A # or // inside a string literal can be misread as a comment, and a let/const inference is a heuristic, not scope analysis. The output is a starting point for a human port, not a build step. Run the transpiled code through your normal tests before trusting it, and treat the annotations list as the work item list for everything the tool would not guess at.
Try it
The tool is live at codeintel.xyz/tools/language-transpiler/ and is the first entry in the Code Transformation block of the tools roadmap. Load the built-in sample to see a nested Python function rewritten into JavaScript with its annotations, then paste your own. To confirm the “no backend” claim, disconnect from the network before you paste anything sensitive.




