Any prior art/existing libs/ideas for localising Racket languages?

For custom langs I imagine this would be somewhat more complicated, but for any s-exp based language certainly and for the base Racket language in particular it's certainly very possible to have "localised lisps" with locale-specific "aliases" for e.g. define, struct, and anything else except for the #lang line in a way that's easy to add new "locale strings" for new modules and methods to the local project and contribute them upstream.

Specifically, in a way wherein, for example, a user struct with name and email fields may either be define as normal (in the default en-US locale assumed in Racket) as (struct user (name email)) and alias it for e.g. Spanish as (localise-struct 'es-ES 'user '(name email) 'usuario '(nombre email)) or some such, or vice versa with e.g. (estructura usario (nombre email)) and localising to 'en-US, but in a way where both user and usario structures return #t interchangeably for user? and usario? and respond interchangeable to user-email and usario-nombre etc.

In particular, I'm not looking for anything to localise Racket values (like those returned by the aforementioned user-email and usario-nombre functions), as that's a solved problem (though, considering this, it might be good to build around one of those solutions?). Custom langs would likely require plugging into the lexer, which might be the way to go in any case?

Really I'm just trying to write lisp interchangeably between multiple languages (rather, I expose simple lisp interfaces to clients and I have a new client who can't speak English), and having some lisp experience I figured Racket would be perfect for the job and even somewhat surprised not to find anything online about it. I'm only just working my way through the Racket guide so I'm very much a newbie Racketeer but I threw an LLM at the problem in hopes of here illustrating my intent, the results thereof which you're welcome to peruse/rewrite/burn with fire I put up on Github (which I understand is traditional for AI slop).

In any case this seems to me like both an important ability and one which suits Racket particularly well, so if there is an existing solution I'd love to just use it, and if there isn't is there anyone willing to collab on an open source lib?

As far as “prior art”, you might be interested in the teaching languages used by the German textbook Schreibe Dein Programm!:

Overall, I think the basic starting point for something like this would be translating identifiers through rename-in, rename-out, and perhaps, if necessary, rename transformers.

The question then becomes, what features do you want beyond that? Someone has been experimenting with renaming keywords, and also automatic renaming (which has pros and cons). Do you want localized syntax error messages? If so, do you want them only from cooperating macros, or do you want to rewrite arbitrary error messages? Racket provides hooks that could support many of these features, it's just a matter of articulating exactly what you want (and how much work you're prepared to do).

Hi, thank you for the insightful response, I wish I had enough German to go through the book you recommended in the original but I'll be sure to enjoy a Google-translated version, so thanks for that, though from what I see this wouldn't be a good approach for what I'm going for precisely.

As in, I want to be able to create domain/client languages on top of #lang racket, but for domains/clients which cover multiple languages but for people who aren't necessarily multilingual. So for a given client who only speaks e.g. he-IL, I want that client to be able to write strictly he-IL s-exps, that is, I care a lot more about having he-IL equivalents for require, provide, struct, class, module identifiers, etc etc, as well as then having any e.g. structs defined in he-IL to have equivalents in the default en-US.

So in any case, per project, I'm gonna need to have some localisation layer for terms and forms for every given project, and my thinking is that extracting from a given project locally-made localisations for some locale for some external package, to then refactor that out in a streamlined way such that one could install e.g. both graph and graph-he-IL and require them together in the localisation layer to be able to then run (תדרוש גרף) in a he-IL file equivalently to (require graph) in an en-US file.

To this end, some base localisations for e.g. 'racket-base-he-ILandracket-he-IL` which are standalone and may be contributed to by anyone are an excellent starting point for any more specific language/module, and so on and so forth all the way down.

To elaborate this in regards to your questions, it's not so much about localizing all Racket errors as it is about providing, for example, per-locale matchers on errors so that, when thrown in a he-IL REPL or else passed to e.g. a web client w a user session in he-IL, to be shown in he-IL in a way that can also then be reported in he-IL and converted back to en-US. I want to make it easy for macros to cooperate, and easy to externally extend macros to cooperate transiently. See also my previous point about the interchangeability of user? and usario? etc.

Insofar as work I'm prepared to do, I'm quite committed in general and for the next few weeks reasonably available for anything up to being able to, on the fly, sit with a client in front of a REPL and/or Racket file in he-IL, and be able to both show them me writing en-US code about their he-IL code (i.e., localise to en-US then require it into an en-US file using the localised en-US module identifier and call functions from that module using localised en-US function names) as well as to add a he-IL localisation on the fly for any non-localised value we bump into, from error messages to external dependencies. The repo I provided also serves as (probably nothing more than) an illustration of this.

I hope this addresses your questions and better articulates my intent. Thank you again for the response! I wasn't aware of rename-in and rename-out etc, seems like they could be great for intermediary "localisation adapter" namepaces, which could be a very elegant solution. Would there be any weird issues using this method for e.g. require and struct? Although, this would be clumsy for e.g. generated struct functions, but this could be solved by something like localise-struct in my initial post or something along those lines.

See also this example racket-localised/examples/struct-localization.rkt at main · wizard-enterprises/racket-localised · GitHub

I hope this is clearer, I'd love to hear your thoughts and answer any other questions or ideas.

Apropos support for multiple native languages, take a look at Hedy.

https://hedy.org/

You will find the language tools provided by Racket to be capable of implementing your idea. I can't help note, that the relatively few english keywords in a programming language usually aren't a problem for a beginner. The hard part is grasping the programming concepts.

Translating the keywords has a downside: it becomes harder to ask for help and searching for solutions online also becomes harder.

Do you plan to translate the documentation as well?

I for one have been annoyed by Geogebra which provides translations of its commands.
But they only update the documentation for the english ones.

Hi, Hedy is lovely!

I definitely agree, documentation is very important, and a half-localised solution leaves room for a lot of confusions. However my case is less for teaching programming and more for bespoke code interfaces for domain language. That is, the important part is moreso the domain language, but when the domain language isn't en-US and the domain experts don't speak English, translated keywords are important to build off of. For my case I'm not planning on any serious code to be written in translated Racket, as it's very easy and usually easier to use English for any serious coding, and interoperability and isomorphism between locales is the whole point.

That is to say, I'm imagining localisation layers, starting from racket-base and racket and building outwards. Any localisation layer should allow localising keywords, error messages, documentation, module identifiers, and anything else (argument names? ~a in formatted strings?) that the user might run into. As in, I'm less worried about translating all the docs and moreso with providing an extendible layer to which anyone can contribute documentation localisations and anything else, and install them as e.g. racket-he-IL or data-frame-es-ES.

As for asking for help, since a localised form is equivalent to its en-US form (where available) and converting to and from locales is part of the core functionality, .it should be trivial to take a localised form and "delocalise" it (to en-US) for a google search or anything.

1 Like

Apropos support for multiple native languages, take a look at Hedy.

https://hedy.org/

You will find the language tools provided by Racket to be capable of implementing your idea. I can't help note, that the relatively few english keywords in a programming language usually aren't a problem for a beginner. The hard part is grasping the programming concepts.

Translating the keywords has a downside: it becomes harder to ask for help and searching for solutions online also becomes harder.

Long ago i the 1970's I worked in the Netherlands, where the prevailing
language was Dutch.
The locals preferred to use a version of Algol with English keywords
rather tha Dutch keywords, but for their own variable and function
names they used Dutch words.
It meant there was almost never a conflict beterrn their words
and the keywords in the programming language.

You may be trying to solve a nonexistent problem.

-- hendrik

1 Like

Hedy’s use makes it clear that there is value (at least in education) in localized programming languages. So this might be a bit too far :slight_smile: