Skip to content
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

Fallback to language-only file if language_territory file DNE #4

Merged
merged 4 commits into from
Aug 18, 2015

Conversation

nexdrew
Copy link
Member

@nexdrew nexdrew commented Aug 17, 2015

Based on yargs PR 231, attempt to better handle "full locales" (e.g. en_US) by allowing y18n to fallback to language-only file (e.g. en.json) if no file exists for the language_territory combination (e.g. en_US.json).

The first commit adds the initial implementation, which is, admittedly, not very efficient since it potentially adds 2 additional file system queries (fs.statSync()) per cached locale. Wasn't sure how to get around this without refactoring quite a bit of code. Note that I created a wrapper for fs.statSync() instead of just using fs.existsSync() directly since the latter is documented as "will be deprecated".

The second commit adds a new configuration option fallbackToLanguage so consumers can turn off this functionality if they don't like it. It's on by default, so that yargs can take advantage of it without any code changes. Not crazy about the config property name.

I'm also not especially crazy about splitting on '_' to splice out the language from the given locale value, but it should probably do for now.

Feedback welcomed!

@bcoe
Copy link
Member

bcoe commented Aug 17, 2015

@nexdrew this is looking good, I'll have some feedback end of day.

@bcoe
Copy link
Member

bcoe commented Aug 18, 2015

One question that comes to mind, rather than simply returning a locale file's path split on _ should resolveLocale explicitly set the locale to the new value?

lookup en_CA, if there's only en.json, setLocale('en') haven't fully thought out what this refactor would look like, but perhaps it would be more straightforward?

var locale = JSON.parse(fs.readFileSync('./test/locales/fr.json', 'utf-8'))
locale.banana.should.equal('banana')
return done(err)
})
})

it('does not write new word to language file if fallbackToLanguage is false', function (done) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might reword this test slightly, it wasn't immediately obvious to me... perhaps:

writes word to missing locale file, if no fallback takes place

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I struggled to name these tests appropriately. Your idea is better. I'll change it.

@bcoe
Copy link
Member

bcoe commented Aug 18, 2015

No huge complaints, I like that we're moving more logic into y18n rather than yargs.

@nexdrew
Copy link
Member Author

nexdrew commented Aug 18, 2015

Regarding this:

One question that comes to mind, rather than simply returning a locale file's path split on _ should resolveLocale explicitly set the locale to the new value?

lookup en_CA, if there's only en.json, setLocale('en') haven't fully thought out what this refactor would look like, but perhaps it would be more straightforward?

I thought about doing this, but I decided against implicitly changing a value that the consumer is explicitly specifying. This behavior just seems wrong to me:

var y18n = Y18n({
  locale: 'en_CA'
})
y18n.getLocale() // 'en_CA' => correct
y18n.__('Hello')
y18n.getLocale() // 'en' => what?

I view using the language-only file more as an interpretation or "best effort" to support the given locale. I can kinda see how this might cause confusion if the consumer was expecting a new file to be written, but in that case, the consumer should explicitly set fallbackToLanguage to false. Otherwise, y18n is just finding and using the closest match.

I could easily be persuaded against this, but that is my rationale. Here's some other ideas for what we could possibly do differently:

  • Keep separate vars for "given locale" and "resolved locale" (or "effective locale") and expose them via API methods.
  • Resolve the locale based on fallbackToLanguage and best-matched file in the setLocale() method (instead of in _processWriteQueue and _readLocaleFile), and call setLocale() in the constructor/configuration function. That would at least make getLocale() consistent; though it might mean keeping a "locale -> file" cache and/or adding "file" to work units in the writeQueue.

I had another idea but lost it during distractions encountered while writing this up.

I'm definitely open to whatever you think is best. My initial implementation is definitely not very elegant. I just think that most systems deal with locales in the 'ab_CD' format (and sometimes 'ab-CD') instead of the 'ab' format, and 'ab' is implied if 'ab_CD' is not directly supported.

@nexdrew
Copy link
Member Author

nexdrew commented Aug 18, 2015

My other idea was to emit an event if we do change the locale value, but I'm not sure there's enough value in that to outweigh the cost.

var frJson = JSON.parse(fs.readFileSync('./test/locales/fr.json', 'utf-8'))
frJson.should.deep.equal({
meow: 'le meow'
})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your confusion now - this doesn't make sense here. It should go in the callback function below. The point is to verify that the fr.json file remained untouched.

Sorry, I will fix.

@bcoe
Copy link
Member

bcoe commented Aug 18, 2015

:shipit: what do you think, minor version bump?

@nexdrew
Copy link
Member Author

nexdrew commented Aug 18, 2015

Yeah, sounds good. I'll get 3.1.0 out tonight, at the latest.

Might see if I can upgrade deps while I'm at it. At least standard.

@bcoe
Copy link
Member

bcoe commented Aug 18, 2015

@nexdrew awesome, thanks; once you have I'll rebase my pull on yargs.

nexdrew pushed a commit that referenced this pull request Aug 18, 2015
Fallback to language-only file if language_territory file DNE
@nexdrew nexdrew merged commit bf1ef9b into yargs:master Aug 18, 2015
@nexdrew nexdrew deleted the lang-code-fallback branch August 18, 2015 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants