-
Notifications
You must be signed in to change notification settings - Fork 14
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
WIP : Lokalise integration - test on Exception #110
Conversation
Thanks for all the work! This is too much for me to review at the moment, if @romaninsh and @PhilippGrashoff are OK with this then so am I :) |
} | ||
|
||
return self::$instance = new static(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this usually written like so?
if (self::$instance === null) {
self::$instance = new static();
}
return self::$instance;
you know, less code and simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pkly Translator is a singleton, all calls to method Translator::_
will be passed to Translator->adapter->_
, you can set an external adapter to Translator following the iTranslatorAdapter interface which require only definition of method _
I think this is the only way to decouple Translator, because is not intended to be used only in atk4/ui.
About the code syntax, there are for sure other point to review, consider it like a concept because it will be the first singleton in the whole atk.
I try to put out code as fast as i can after last friday discussion, because we need to discuss about this, which is a controversial argument in the Team.
Yes, yes, I wrote that before I noticed the adapter in the code for the Translator. If you'll be discussing translation as a whole, mind if I join in? Do you have the dates and links listed somewhere? |
@pkly our weekly hangouts are at 6pm London time on thursdays. Of course you can join in :) |
is a pleasure to have one more in, @romaninsh changed work and is a little bit busy, but we are trying to continue with the meeting that speed up the whole process. Last time we made a meeting directly in gitter, it was good and @gowrav-vishwakarma popup with an idea about definition of what has to be translated in objects suggesting to define it an array like : public $translate = [
'properties' => ['caption']
'fields' => ['name','sex']
'template' => ['area']
]; For now i think the subject to be discussed is the implementation of the first singleton in ATK, which, like i said before is a change too big to be discussed without the whole team. |
Alright, I'll try to be there (on gitter anyway). I'm mostly interested in implementation of this because of how I'm integrating atk4 into the stuff we're writing, and we need translations. I've already bodged them in there once, but I'm changing the library we're using to the one I'm writing atm. which is a port of i18next. |
So since this is still in the works, I'd like to know if it's trying to be compatible with any kind of syntax? I believe there's been keys like I guess extracting all that data is rather painful, but still. |
There is no standard, just stay simple on core translation i think we can accomplish something near that.
Namespace are optional, deep definition and context too.
it's a start we can see how move further, i suggest use keys because with keys we are much compliant with other translator, everyone has special reserved chars and special format. With key in place of phrases everyone can added a translator much easy, otherwise is a
Few days ago we speak about adding backend caching like redis, when we add it to ATK will be much easier to cache heavier procedure for production, but for core translations is not a so heavy task to be done with this simple implementation. |
src/Exception.php
Outdated
@@ -41,6 +56,8 @@ public function __construct( | |||
$message = array_shift($this->params); | |||
} | |||
|
|||
$message = $this->_($message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we won't have access to $api yet ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also - lets move to $app->caughtException() - or whatever it's called now.
src/Exception.php
Outdated
$output .= "\n\033[1;31m-------------------------------------------------------\n"; | ||
|
||
return $output."\033[0m"; | ||
return (string) new Console($this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possibly pass translator inside this.. ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about default callback here if exception is occured inside?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
App wouldn't really be available in here though, would it? So the singleton is the only option left.
src/ExceptionRenderer/Console.php
Outdated
{ | ||
$text = <<<TEXT | ||
\e[0m{FILE}\e[0m:\e[0;31m{LINE}\e[0m {OBJECT} {CLASS}{FUNCTION_COLOR}{FUNCTION}{FUNCTION_ARGS} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
love this ;)
public function _($message, ?array $parameters = null, ?string $domain = null, ?string $locale = null): string | ||
{ | ||
if (isset($this->app) && method_exists($this->app, '_')) { | ||
return $this->app->_($message, $parameters, $domain, $locale); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we should keep it so we can user have control of translating process in the app.
(those 3 lines), the rest can fall back to singleton.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I more or less second this
As for the talk in the meet, I'd only like to say a few more things: It would be more than enough to have a few namespaces for atk, for example: |
i add the method : Lines 233 to 236 in cce424e
for the Exception specific to "inject" the translator and translate the needed translations |
Codecov Report
@@ Coverage Diff @@
## develop #110 +/- ##
=============================================
+ Coverage 99.33% 99.39% +0.05%
- Complexity 387 420 +33
=============================================
Files 21 22 +1
Lines 899 987 +88
=============================================
+ Hits 893 981 +88
Misses 6 6
Continue to review full report at Codecov.
|
Didn't we talk about this during the meet and @romaninsh specifically asked to not translate this property at all (which I agree with completely), but instead translate it when rendering (so that'd be in |
didn't understand but to do that we have to pass it like this? If you understand it better, can be better this way? public function getHTML(?ITranslatorAdapter $adapter=null)
{
return (string) new HTML($this, $adapter);
} |
That, or you could just add a function like public function setTranslationAdapter(?ITranslationAdapter $adapter = null) {
$this->adapter = $adapter;
}
// and then
public function getHTML(): HTML {
return (string) new HTML($this, $this->adapter);
} Although just adding another function like public function getTranslationAdapter(): ITranslationAdapter {
return $this->adapter ?? Translation::instance();
} would also remove the need to pass the adapters to Also please use more of the |
there is no need to have getAdapter, because or is set (already configured) from outside or is Generic in Translator and is managed by this, adapter act as a repository nearly passive, the active part is Translator.
I understand, but in many cases i prefer early exit to leave space for more conditions to exit before return. |
Composer error
no more happens locally, but in travis still happens, anyone ideas? |
locally works
This reverts commit 3b62e23
If someone can do something on this "composer issue". IMHO the best option to avoid at all this problem is to remove atk4/data dependency and move in atk4/core all the locales, in a directory structure like :
Core is a base dependency. |
I'd go with /language/namespace.json [or other] but yeah that's fine with me, I prefer that to the alternatives honestly. |
i agree with you but i speak strictly for atk translations, the actually hardcoded, did you agree on the rest of modifications done after your comment? To add custom translation with specific namespace (domain) can be used this 2 methods in generic : core/src/Translator/Adapter/Generic.php Lines 115 to 154 in a7906aa
What do you think there is everything in place? |
$output .= "\n\033[1;31m-------------------------------------------------------\n"; | ||
|
||
return $output."\033[0m"; | ||
return (string) new Console($this, $this->adapter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still wondering if it wouldn't be better to simply add a getAdapter()
method to Exception
instead of passing this argument 4 times. Unsure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is a specific renderer that needs 2 args to do his job and is internal, i think is ok
|
||
public function __construct($exception, ?ITranslatorAdapter $adapter = null) | ||
{ | ||
$this->adapter = $adapter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I said above, maybe don't bother with this?
return $this->output; | ||
} catch (\Throwable $e) { | ||
// fallback if Exception occur in renderer | ||
return get_class($this->exception).' ['.$this->exception->getCode().'] Error:'.$this->_($this->exception->getMessage()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe translate the 'Error:' string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe, but probably using a key for common words like this, i suggest exception_string_error
if (is_object($val) && !$val instanceof \Closure) { | ||
return isset($val->_trackableTrait) | ||
? get_class($val).' ('.$val->name.')' | ||
: 'Object '.get_class($val); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe translate the 'Object' string here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe, but probably using a key for common words like this, i suggest exception_string_object
public function _($message, array $parameters = [], ?string $domain = null, ?string $locale = null): string | ||
{ | ||
return $this->adapter | ||
? $this->adapter->_($message, $parameters, $domain, $locale) | ||
: Translator::instance()->_($message, $parameters, $domain, $locale); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a getAdapter
or getTranslationAdapter
method would be added to the exception class this could be basically removed.
Mock implementation in the Exception class:
public function getTranslationAdapter(): ITranslatorAdapter {
return $this->adapter ?? Translator::instance();
}
which could be later used here like so:
if ($this->exception instanceof \atk4\core\Exception) // Maybe make it into an interface instead for use in exceptions, or a trait
return $this->exception->getTranslationAdapter()->_($message, $parameters, $domain, $locale);
// We don't wanna translate other exceptions
return $message;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translator::instance()
is not an ITranslatorAdapter
, it can be because is conform to Interface but is not an ITranslatorAdapter
, because is inteded to be used with the setted ITranslatorAdapter
Why added something that is intended to stay there forever after set?
Translator -> setAdapter ->_($translate)
or
new Adapter -> configure adapter...
Translator -> set adapter (already configured) -> _($translate)
Probably i'm too defensive, but IMHO if you put getTranslator you leave too much space for possible strange and wrong usage of the class
$path = Locale::getPath(); | ||
$this->addDefinitionFromFile($path.$locale.'/atk.php', $locale, 'atk', 'php-inline'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably shouldn't delegate this to atk4\data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree even more because to test it, i encounter circular dependency in composer which i think it will knock to our door in the future
in composer i add : "atk4/data": "dev-lokalise-2019-09-28_17-10-29"
because i need : https://github.com/atk4/data/blob/lokalise-2019-09-28_17-10-29/src/Locale.php
to get the folder of the language definitions path.
I create a singleton Translation with an interface adapter where all the call to _ will come, to allow replace the default Translator with another.
I change the structure of the Lokalise export, because usually every Translator or most of them load with definitions with this structure {root-folder}{language-code}{translations-files}
Cleaned up some things related to Translations.
Removed Symfony Test, will readd later with TranslatorAdapter implementation.
It works even for plural forms, but need some clean up and discussions, like how to add more translations and how to define a different path to load translations, probably i need to split Adapter\Generic in Adapter\Generic that pass calls to _ method to a GenericTranslator.