-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tests to i18n package #193
Conversation
Just a question, why don't you externalize translations and use yaml or something like that, it would be easy for anyone not knowing go to provide a translation for his/her mother tongue and you could easily provide a ready to fill template ? |
I know nothing about dutch but is it valid or something forgotten : https://github.com/jesseduffield/lazygit/blob/master/pkg/i18n/dutch.go#L126 => |
Thanks for doing this! see the discussion here around using external files #137. The general idea was that you couldn't bake external files into the binary so it was better to do it in go. English and Dutch share the word 'is' so that's a valid translation :) |
Ah ok, so I learnt something about dutch. Yeah I get it but I was thinking more to a build step something that pick a yaml for instance and dump a structure, maybe something that could take advantage of code generation like here : https://blog.golang.org/generate |
And also just for your information rakyll did a tool for that purpose (embedding files in a binary) : https://github.com/rakyll/statik the example in the readme is for a web server but I guess you can think of other usages. |
I think that setting environment variables here could cause some big problems if tests ever crash mid-way such that the teardown doesn't have the chance to run. Instead, I think we should just define a LanguageDetector interface which implements the 'DetectLanguage()' method and then we can use a wrapper for jibber jabber's method in the app, and define a mock version in the test. I've got a patch that you can apply on this PR to make the necessary code change in the i18n package:
|
What do you think about moving this :
inside the moving that in another function :
so something like that (just a draft so don't pay too much attention to details) :
so you could just have a lightweight NewLocalizerWithLanguageDetector, you would be able to instantiate the Localizer for testing purpose and you won't have to ask explicity outside for the LanguageDetector which is an internal dependency |
yep that sounds good! |
@jesseduffield have you seen my comment above about code generation ? |
@antham The comment you placed looks good to me. When translating |
If you want to mock jibber jabber, you should keep that in the test file, and not in the actual package, otherwise the code becomes tightly coupled to that library. |
I not sure if I get correctly what you mean, but here in my opinion, you have to isolate that |
What I mean is that if for the sake of argument we want to swap out jibber jabber for something else (i.e, dependency injection), w.r.t. the error, it should either be replaced with |
Yeah I think we shouldn't check at all. If the DetectLanguage method returns an error, we should log the error and just use 'C'. There's no point handling it in any special way. So we'd end up with:
That way we can pass in the mock in the test where we make DetectLanguage() return whatever we want it to |
regarding code generation yeah if we can make that work that'd be awesome. I'm probably not going to have time to look towards implementing myself but if you (or anybody else) is down for it I'll definitely help out however I can |
@remyabel Yes we can add an interface, but I think it doesn't really serve any purpose. You don't need it to achieve decoupling, you export nothing about that outside and you have really a simple implementation with one-to-one relationships easy to deal with if you change a library for another, I think if things become more complicated (i don't think so but I can get it wrong) you could add interfaces at this time if you really need to. @jesseduffield I could have a look yes for this generation, |
I mentioned interfaces because it's commonly used in mocking libraries, see here. |
Sure but I can achieve this in another way here. I propose to change the package with what we just talked about to get a clear picture and if you think it's bad, I will change the code. |
@remyabel @jesseduffield I have rewritten everything following the conversation |
I added a little refac to addBundles as well |
As you have the language you can't load only the required translation file ? |
@antham you've convinced me! Looks like this is a good pattern: if you only need to mock a function, may as well just let the tested method receive that function. If you need to mock multiple functions, you should wrap stuff in an interface. That sounds reasonable to me. Good job on the refactor as well! I'm happy to merge this, but I'll give @remyabel the chance to have a look and give his input |
LGTM |
I would say interface is not a matter of mocking, through interface you achieve decoupling which lead to easier testing but it's a side effect not a primary purpose, the primary purpose of an interface is to be a contract, adding interface is adding an abstraction layer which could lead if you add it without care to have a cumbersome codebase. |
@antham that makes sense :) mergin now |
No description provided.