So, I’m working on implementing internationalization on a project soon to be online.
I’m using RW’s i18n implementation and I’d like to be able to pass its language value to all of my graphql queries.
I understand ApolloLink enables a middleware functionality here so I gave it a shot:
The code is executed but on the server side this is nowhere to be found.
I’m using a directive to handle the heavy translation work and I would expect its context variable to reflect my modification and display expected-language:
// api/src/directives/translate/translate.ts
import {createTransformerDirective, TransformerDirectiveFunc,} from '@redwoodjs/graphql-server';
export const schema = gql`
"""
Use @translate to transform the resolved value to return a modified result.
"""
directive @translate(language: String) on FIELD_DEFINITION
`
const transform: TransformerDirectiveFunc = ({context, directiveArgs, resolvedValue}) => {
console.log(context)
// [...]
}
const translate = createTransformerDirective(schema, transform)
export default translate
console.log(context) is impervious to my any attempts.
What am I missing? Should I do it a different way?
I have the same need. This is how I solve it right now
export const beforeQuery = ({ categoryId }) => {
// This will be executed in the context of a component, so it's fine to
// use hooks here
// eslint-disable-next-line react-hooks/rules-of-hooks
const settings = useSettingsContext()
return {
variables: {
categoryId,
lang: settings.state.language,
},
}
}
Thanks for your reply @Tobbe , this is what I have indeed today but as you say it’s not pretty.
That’s for the new website for redwood, so I’m sort of desperately looking for some neat graphql usage, but I have no experience with links and haven’t managed to get them working in my researches:-/.
@simoncrypta mentioned that this could be handled as authentication in redwood, which would be another interesting thing to try but that would require framework modification to the best of my assumptions.
This is probably something we should discuss in the Core Team. But everyone so busy with v1 prep it’s going to be difficult to get any attention on it.
@simoncrypta What do you think? What’s the next step here?
Also, useMutation might need the language, depending on what data it returns.
Definitely! I think we should always have something like CurrentLanguage and maybe CurrentLocalisation accessible from the API side to be able to write the right logic for any Query or Mutation in GraphQL.
@simoncrypta What do you think? What’s the next step here?
Since at the end the focus is really about the DX, I think it is worth to give a try by adding to the tutorial an unofficial bonus step with i18n and the DX we want. After that, if we have a consensus, I think it is worth to discuss if it should be part of the V1 release or not. Are you with that ? I can start something today.
I got a better understanding of what you’re trying to do with ApolloLink and Directive, and I think I finally know what’s the problem.
ApolloLink like you said works, but the response should be somewhere in the function handler inside event.headers['expected-language'] and I don’t realty know how you can get that for Directive.
However, I don’t think we need something like that for Redwood since we will never translate anything from the API.
Compare to some other framework, our API don’t serve HTML with template data, and like @danny had said to me before, every translation of string should be done in the front-end. When we got generic message from the API to translate, the best thing to do is to create the translation string with a code like on the example for failure with errorCode : Docs - Cells : RedwoodJS Docs
So at the end, we only need to specify language to query or mutate for something in the database, and in this case, I think that query parameter is the way to go.
I will try to write a continuation of the tutorial with i18n as soon I can to show every use case possible with translation and localization.
Really? Danny said that? I thought I was the only one who held that belief
But even I have had to change my mind a little bit. I have a project where I’m doing machine translation. And I think that’s best done on the API side. It’s too inefficient (and expensive) to send the same string off to Google Translate over and over again for every single user on the web side. So I do the translations once on the API side, and then save the translations to my DB so I don’t have to do them again. And another use case is if you’re doing something like a CMS where your users can provide content in multiple languages. In that case you don’t want the translations in your en.json, fr.json, etc, files. You’d want them in your database.
So my new take on this is more nuanced. I still believe you should prefer to do the translations on the web side whenever possible. But sometimes you have to do translation related things on the backend too. And when you do, you should prefer to limit it to just picking the right translation from a DB table. But I do realize there are probably exceptions to that rule too.
I’m conflicted now :D.
I also firmly believe that any non editable/dynamic translation should be handled on the frontend side: ui text + api errors are the obvious case.
However I do not know a clean way to handle editable translation, content translation from the frontend, as @Tobbe describes it. Either it comes from the DB, or we’d allow to edit files from a backoffice interface, which I find rather unreliable.
So… I can move forward with the beforeQuery solution if we agree on it being a sound way to do it. Which leaves me with the question: what about the idea of passing localization & language as context? I thought it was pretty neat and that would make an obvious case of it.
Update, there’s still a lot to do here and there for the launch, and this can be resolved with beforeQuery and a directive - I kept both for now.
Still opened to improvements though