Closed Jacob-Finn closed 4 years ago
Hi,
I'm not sure to understand why you would do such thing, but wouldn't setting outputPath
to extractedTranslations/{{locale}}.json
be what you're looking for? Not sure it would work as expected, but it's worth a try I think.
If you encounter some crash, please provide reproduction steps.
@gilbsgilbs Sorry for the very long delay in responding, I haven't had a chance to come back to this issue till today, As for why I would want to do such a thing, I use a ducks structure format, where my components and screens are separated. So my file format looks something like this
Features
Screens
So as you can see, I have a lot of JSON files containing keys in lots of different places, this makes it easier to work on a feature/screen at one time without going through a giant JSON file for translations. Why I need this feature is that I thought this extractor would be able to extract all my keys out of these JSON files in my entire project and organize them neatly all together, that way sending my translation files to an external source to be translated would be as simple as running a command and sending off the JSON file, rather than manually having to make a giant JSON file to send off by going into each component and each screen to copy and paste the keys.
I followed your advice and now it does seem like I am getting a collective JSON file under
extractedTranslations/en.json, but whenever I open the JSON file, it doesn't appear like the extractor is finding any of my key's default values that I have kept in the JSON files.
{ "date": "", "login": "", "placeHolder": "", "welcome": "" }
I might be idiotic, but I still don't get the desired workflow. I'm not sure if you'd want this plugin to map translation file path depending on the location of the source file (but how would it know?) or if you'd want to create a "giant JSON file" or both (but how would you combine them?). If by any chance that is of help, specifying values in the giant JSON file is something you'd only have to do once. The plugin should not clear or overwrite values that already exist in that file. But I don't think you wanted to get rid of your JSON splits so I don't know, I don't get it, sorry :man_shrugging: .
In any case, unless I really missed something (which I probably did), that sounds quite convoluted and specific to me. That's probably not something I'm willing to have built-in support for right now (unless somebody can come up with an elegant and versatile solution). The way I'd like to address complex workflows like this would be by exposing a plain JS API that would let you hook into the exporter to export what you want where you want (using actual JS code rather than configuration). But that's not done yet.
Might be very similar to https://github.com/gilbsgilbs/babel-plugin-i18next-extract/issues/76.
@gilbsgilbs I was actually able to solve this issue by creating my own importer/exporter using Node. Sorry for all the confusion! I will leave this issue open incase you want to keep it for some reason, but otherwise I'd be fine with closing this issue.
In fact, I'd like to understand how people use i18next. Sure this plugin could expose some JS hooks that would do the trick, but I believe there could be pragmatic solutions that could solve legitimate and common workflows (like the one described in #76 and maybe in this issue) without the need to write any code.
In particular, being able to specify an object as output path could be of help in some cases:
{
"outputPath": {
"./src/Features/Login/LoginForm/**/*.{js,jsx}": "./src/Features/Login/LoginForm/locales/{{ns}}/{{locale}}.json",
"./src/Screens/Login/**/*.{js,jsx}": "./src/Screens/Login/locales/{{ns}}/{{locale}}.json"
}
}
I don't think this would be very bad maintenance-wise. I'm just unsure whether it would really be used.
@gilbsgilbs I can't currently share my project that I'm working on as it isn't allowed to be released to the public, but I'll try and put together a rough draft sometime later today to show you what I mean, as this is something that I feel it is easier to show than tell what I'm talking about.
Hi @Jacob-Finn, I could be interested in the solution you found or built yourself to solve your problem. I'd also like to split my locales into several files across my projets (for instance, let's say one file per page and per locale), but I can't quite figure it out. Any help you can spare would be appreciated 👍
@acidoxee @gilbsgilbs My solution: https://pastebin.com/L4xcQgTc (requires nodes).
Basically it will search through all folders and subfolders under
../../features
and ../../screens
and then store all the JSON keys it finds into a masterTranslation.json folder, this can then be sent to a translation service containing all your keys for your project. The lines that you would need to change per project are lines 5, 6, and 25. To run the script I just added a command to my package.json: "extract-translation-keys": "cd src && cd utils && cd i18next && node generateLocaleMaster & cd ../../../"
Hopefully that is clear enough as to what is happening, if you need anymore help feel free to tag me again @acidoxee.
Thanks for the quick reply @Jacob-Finn. Your script does seem interesting and would solve some of our problems.
Unfortunately, I don't think your solution can be integrated with existing key extraction tooling such as this plugin, since those tools themselves would need to be able to extract missing keys to the proper split locale files, which (correct me if I'm wrong) is not the case.
I guess the only case where this wouldn't be a problem is if you split all your locales per component, since the missing keys in the component could immediately be identified by looking into the adjacent locale files, but boy would that be a PITA to manage in the long run 😄
Since manually extracting missing keys and not having automatic linting would be a bigger pain for us than not having several-folders-splitting functionality, for now we'll stick to this Babel plugin, which at least does a great job at... well... extracting keys from everywhere :)
Thanks anyway for your help!
@acidoxee would something like this suggestion solve your issue?
Yes actually, that would probably be a first step towards the solution we're looking for. My bad for having overlooked that answer 👍
I'm just wondering if having to maintain the correspondance by hand could ever become a burden. A simpler binding that wouldn't require any maintenance would maybe be better in the long run. For instance, by using the namespace to bind to a page folder (with the exact same name obviously) like so:
{
"outputPath": "src/pages/{{ns}}/__locales__/{{locale}}.json"
}
This is already possible today with your plugin. But it doesn't account for special namespaces that don't have anything to do with pages, such as common
, errors
and similar stuff, which we'd like to keep elsewhere. In that regard, a JS hook could solve the problem by allowing us to customize the output path with a function based on the namespace, locale and file path of each key found by your plugin.
Then, the re-packaging of all those split locales into a single file per locale could be handled with @Jacob-Finn's solution, that could be triggered in CI/CD just before the final build. Does this workflow look legit?
JS hooks are definitely part of the plan but it may take some time to build a good and stable API. I want to address most frequent use-cases without requiring the user to write JS code and I also want to fix some of the remaining bugs before opening the hook API. Therefore it might take a while until we get there.
It seems that splits are quite demanded for both monorepos setups (which are very common) and per-folder translations, so it makes sense to have a dedicated feature for this IMO.
I'll not be able to work on this very soon, but if somebody wants to contribute, I'll look into it!
Closing this in favor of #76.
This might already be a feature and I just haven't been able to figure out how to get it work successfully, but currently in my project I am storing keys inside of JSON files, for example login.JSON might contain:
{ "login": { "placeHolder": "Phone number", "login": "Login" } }
while my common.JSON might contain:
{ "common": { "welcome": "Welcome to the Home Menu", "language": "You are now using English", "date": "The current date is {{date, 'LLLL'}}" } }
I basically want to be able to combine these into a single JSON file with their namespaces and keys still intact, but whenever I try to have i18next-extract target JSON files, I usually get an error on the colon ':' where a semicolon is expected ';'.