4

这个问题是关于使用dust.js 模板系统和子上下文中的数据路径。我的意图是使用字符串的键映射来支持 i18n。

给定这样的数据:

{i18n : { firstname : "First Name" },
 people : [
    {"name" : "Moe"},
    {"name" : "Curly"}
 ]}

在尘土中,您可以使用部分来列出每个人:

{#people}
    {name}
{/people}

您可以使用路径来访问 firstname i18n 字符串:

{i18n.firstname}

但以下不起作用:

{#people}
    {i18n.firstname}: {name}
{/people}

事实上,文档特别说:

为了避免脆弱和混乱的引用,路径永远不会回溯上下文堆栈。如果您需要深入了解父上下文中可用的键,请将键作为参数传递。

所以我尝试将密钥作为参数传递:

{#people i18n=i18n}
    {i18n.firstname}: {name}
{/people}

但这不起作用。当我在灰尘主页上对此进行实验时,我看到编译后的模板有以下代码:

"i18n": ctx.get("i18n")

Which makes me think the above example should work fine.

So what gives? How can I make this work?

Note: The following does work:

{#people firstname=i18n.firstname}
    {firstname}: {name}
{/people}

But this doesn't work well if you need to access a lot of i18n keys within the people context.

4

2 回答 2

5

Paths can be used in keys and in sections to specify where you want Dust to look for keys. To understand how and when to use paths, you should first understand how Dust looks for keys when there are no paths. You might want to sit down.

When searching for keys, Dust first looks in the current context, then looks in each parent context until there are no more parents to search in. If no key is found, Dust does nothing (unless you are using an Exists or Not Exists Section). If Dust finds the key, it stops searching and uses the given value. That's not too foreign, right? That's how JavaScript looks for variables in execution environments.

However, instead of looking up the tree toward root, when a path is used, Dust only looks at children. This is best illustrated with an example.

JSON:

{
  "i18n": {
    "firstname": "First Name"
  },
  "name": "My Dust Template",
  "firstname": "Surprise!",
  "people": [
    {
      "name": {
        "firstname": "Moe",
        "lastname": "Howard"
      }
    },
    {
      "name": {
        "firstname": "Curly",
        "lastname": "Howard"
      }
    }
  ]
}

And the Dust:

Dust Template:

{! Show the name of the template !}
{name}{~n}
{#people}

  {! 
     As you noted, the following will not work, because 
     when using a path, Dust only searches
     deeper into the JSON. The output will be:
     ": Surprise!"
  !}
  {i18n.firstname}: {firstname}{~n}

  {!
     To get your i18n string, you need to look up the 
     stack instead of down. This can be done by using a
     section without a path, as follows. The output will be:
     "First Name: Moe"
     "First Name: Curly"
  !}
  {#i18n}{firstname}{/i18n}: {name.firstname}{~n}

  {! 
     Note that we successfully used the path to 
     get the firstname of each of the people.
  !}
{/people}

[EDIT]: For more info, check out this wiki page from the LinkedIn fork of Dust: https://github.com/linkedin/dustjs/wiki/Where-else-does-Dust-search-if-the-value-is-not-defined%3F-A.K.A.-Dust-Scoping

于 2012-08-08T18:37:36.260 回答
3

if this is your template:

{#people i18n=i18n}
  {i18n.firstname}: {name}
{/people}

here's how your context stack looks like as it iterates through your 'name' array

{ your original context}
i18n -> firstname: "First Name"
name -> "Moe" 

what happens is, when you define a parameter, dust pushes into the context stack all the parameters you defined. then when it finds an array in your context, dust pushes into the stack, one at a time, all the items in the array.

so now when you define a path context within the section, even though you've passed i18n in as a parameter, the i18n context is still up in the context stack, and when you try to access i18n with a path, like {i18n.firstname}, dust wouldn't find it, coz it has to backtrack to find it, and getPath doesn't do backtracks. the get method, on the other hand does backtrack, so that's why, when you do this:

{#people firstname=i18n.firstname}
  {firstname}: {name}
{/people}

it works, because it's accessing the firstname within the section with a get method. hope you understand what i'm trying to say.

what i'd do is define a helper method that takes in a section like so:

{#people}
  {#i18n}{firstname}{/i18n}: {name}{~n}
{/people}

and define the method in your context (or push it to your global context [defined with makeBase] to make it a global helper) like so:

i18n: function(chunk, context, bodies, params){
  var trans = context.get(translation); //or whatever name you give to your i18n list
  chunk.render(bodies.block, context.push(trans));
  return chunk;
}

tested this on the dust website and it works. the advantage to this approach is you can now format your i18n output within the confines of the section. also, it would be good to define both the helper and the i18n list in your global context, so do use makeBase for that. all the best.

于 2012-08-08T12:54:04.460 回答