-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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 I18n syntax error translation #241
Conversation
require File.join(File.dirname(__FILE__), '..', 'lib', 'liquid') | ||
|
||
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')) | ||
require 'liquid.rb' |
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.
Why this change?
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.
Doesn't handle running single test files nicely otherwise.
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.
Hm, didn't have problems with that before. What do you mean exactly?
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.
liquid (i18n-error) Σ ruby -Itest test/liquid/i18n_test.rb
/opt/boxen/rbenv/versions/1.9.3-p448/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- liquid/version (LoadError)
from /opt/boxen/rbenv/versions/1.9.3-p448/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/sirup/Dropbox/Code/liquid/lib/liquid.rb:48:in `<top (required)>'
from /opt/boxen/rbenv/versions/1.9.3-p448/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /opt/boxen/rbenv/versions/1.9.3-p448/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/sirup/Dropbox/Code/liquid/test/test_helper.rb:13:in `<top (required)>'
from /opt/boxen/rbenv/versions/1.9.3-p448/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /opt/boxen/rbenv/versions/1.9.3-p448/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from test/liquid/i18n_test.rb:1:in `<main>'
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.
Do you run ruby -Itest -Ilib test/liquid/i18n_test.rb
? I rarely see that.
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 had the same problem before. I would, however, have this change in a isolate commit.
Hm, haven't taken a very close look, but considering we only have like 5 error messages at most, this seems very overkill. Also, I don't want to call it "I18n", that's a bit confusing. |
@phoet, thoughts? |
@@ -0,0 +1,46 @@ | |||
require 'yaml' | |||
require 'delegate' |
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.
What's this for?
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.
Previous attempt, I forgot to remove it.
Hm, ok, on second thought, maybe it's not overkill. Seems nice actually. @arthurnn, @dylanahsmith, any comments so far? |
@@ -41,7 +41,9 @@ def register_filter(mod) | |||
end | |||
|
|||
# creates a new <tt>Template</tt> object from liquid source code | |||
def parse(source) | |||
def parse(source, options = {:locale => "lib/liquid/locales/en.yml"}) |
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 this is not the right place to define default options. There is two ways to parse a template: Template.parse(...)
and Template.new.parse(...)
. You only catch one of them. Also, your I18n.global
thing doesn't seem to be thread-safe (two threads using different languages). Instead of using global variables, why not store this stuff in the Liquid context?
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.
Yeah, it's not thread-safe. It hit me when I went to bed I could store the I18n
object in the Liquid context registers to access it anywhere, but haven't actually implemented it yet. I think this is what makes it not overkill, that you can have these objects around. It's a pretty simple class, too.
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, will this relative path work once this thing is packaged as a gem (and the application itself doesn't provide a locale file)?
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 in the test you wanna make it absolute.
Since I18n is self-referential, it can stack overflow if the error message doesn't exist in the database. There are three solutions:
|
|
||
private | ||
def interpolate(name, vars) | ||
name.gsub(/:(\w+)/) do |
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 feel like this might match too much. Maybe we should add the possibility to escape :? Like /[^\]:(\w+)/
maybe?
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.
edit: Good point!
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.
Just for the case that someone wants to include colons in their error messages. Dunno. Not a big deal.
@fw42 What should be done? Thoughts on whether the logic in Template#initialize should be moved? |
Wait for one of the three people I asked for comments to actually say something :P |
Guys, can one of you please take a look? @arthurnn, @dylanahsmith, @phoet, @trishume |
@@ -101,7 +102,7 @@ def render(*args) | |||
when nil | |||
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits) | |||
else | |||
raise ArgumentError, "Expect Hash or Liquid::Context as parameter" | |||
raise ArgumentError, registers[:locale].translate("errors.template.argument_hash_or_context") |
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.
why not using the .t
method in 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.
I don't think this message would be expected to ever how up in rendered liquid output, so do we really need to translate 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.
Do we only need to translate syntax errors? I don't know Liquid well in terms of what could be useful to translate besides that. But yes, agreed. 👍 Shouldn't use this everywhere, just where it's needed to not clutter the locale file too much.
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.
There are a handful of errors other than SyntaxError. Try grep raise -R lib
in the repository.
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.
Sure, but which of those do we actually need to translate? Should they all be translated?
I'm still not sure about calling this I18n. It's confusing. |
unknown_translation: "Translation for :name does not exist in locale" | ||
undefined_interpolation: "Undefined key :key for interpolation in translation :name" | ||
template: | ||
argument_hash_or_context: "Expect Hash or Liquid::Context as parameter" |
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.
Doesn't the :Context
in this get treated as an interpolation?
Maybe a different interpolation character should be chosen, colons are common in plain english and code.
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.
It might be clearer if we use /%{\w+}/ syntax for interpolation.
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.
That's true. There is support for escaping, but it feels really awkward here. I support your idea @dylanahsmith, @fw42 any strong feelings about :symbol
?
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.
Nope, no strong feelings
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 like '%' as the escape character as well, for consistency with C printf. Or maybe for the recursive lulz the strings could be interpreted using Liquid.
Looks pretty good. I agree about not naming it I18n though, maybe 'Internationalization'? |
I like the |
private | ||
def interpolate(name, vars) | ||
name.gsub(/([^\\]):(\w+)/) { | ||
raise TranslationError, translate("errors.i18n.undefined_interpolation", :key => $1, :name => name) unless vars[$2.to_sym] |
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.
Instead of raising, maybe just don't interpolate?
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.
Would you ever want to put the interpolation syntax if the key is not passed? Shouldn't this act as much like Ruby as possible?
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.
Hm yeah I guess you are right
I was under the impression that most people associate the term "I18n" with one specific implementation of Internationalization (the one that comes with Rails). I didn't know it's just a shorter synonym. Feel free to use it then. |
It is indeed just a short term, on my old times of java development, we used to use I18n for classes and all that. http://struts.apache.org/release/1.3.x/apidocs/org/apache/struts/tiles/xmlDefinition/I18nFactorySet.html |
@fw42 sorry, i am quite bussy right now and on vacation from thursday on. will have no time to review! |
Really like the lib/liquid/template.rb now.. 💚 ❤️ 🍍 ❤️ 💚 . Probably before merge we would want to squash those back and forth in one commit, but besides that I like it. |
Also need to actually add the translations. :-) Still don't know whether every exception should be translated, or just syntax errors. See thread above. |
This looks great, I like the interpolation syntax. In terms of translations I think it should be every error that can be produced by problems with a template, which means any error that a user rather than a developer will see. That means syntax errors as well as some other errors like 'missing filter'. |
I'll wait with this until the new parser is merged in. |
@fw42 Agreed! Now that this PR encompasses both the new parser and fancy errors we can just merge this one and close the other. |
I would rather have two separate merges (first the parser branch, then this one). ⛵ 💨 |
@fw42 agreed, that's cleaner |
end | ||
|
||
def tokenize | ||
@output = [] | ||
|
||
loop do | ||
while !@ss.eos? |
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.
What's this? Why is this PR changing lexer code?
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.
That's weird.. :s Bad rebase? @trishume any ideas? You changed this recently?
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 saw that too, I have no idea why. If you look at lexer.rb
in master right now it has the changes that this PR is supposedly adding.
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 just a GitHub UI fuckup? Can you check manually before merging?
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.
You could do the merge on your computer instead of in the Github UI I guess...
Couple of small comments, other than that, 👍 |
Add I18n syntax error translation
Simple possible implementation of I18n support for Liquid errors, as requested in #18.
@fw42 please take a look.