react-i18nliner
Advanced tools
Comparing version 0.0.6 to 0.0.7
@@ -43,2 +43,7 @@ jest.autoMockOff(); | ||
it('doesn\'t merge leading or trailing standalone elements with keys', function() { | ||
expect(subject('<div translate="yes"><input key="user_1" /> versus <input key="user_2" /></div>')) | ||
.toEqual('<div><I18n.ComponentInterpolator string={I18n.t("%{user_1} versus %{user_2}", { "user_1": "%{user_1}", "user_2": "%{user_2}" })} user_1={<input key="user_1" />} user_2={<input key="user_2" />}>$1</I18n.ComponentInterpolator></div>'); | ||
}); | ||
it('absorbs wrappers into placeholders if there is no other content', function() { | ||
@@ -49,2 +54,7 @@ expect(subject('<div translate="yes">hello <b>{user}</b></div>')) | ||
it('users the outermost key when absorbing wrappers into placeholders with no text content', function() { | ||
expect(subject('<div translate="yes">hello <b key="name">{user.name}</b></div>')) | ||
.toEqual('<div><I18n.ComponentInterpolator string={I18n.t("hello %{name}", { "name": "%{name}" })} name={<b key="name">{user.name}</b>}>$1</I18n.ComponentInterpolator></div>'); | ||
}); | ||
it('creates placeholders for expressions', function() { | ||
@@ -60,2 +70,12 @@ expect(subject('<div translate="yes">hello {this.props.userName}</div>')) | ||
it('uses the empty components\'s key as the placeholder name', function() { | ||
expect(subject('<div translate="yes">Create <input key="numAccounts" /> new accounts</div>')) | ||
.toEqual('<div><I18n.ComponentInterpolator string={I18n.t("Create %{num_accounts} new accounts", { "num_accounts": "%{num_accounts}" })} num_accounts={<input key="numAccounts" />}>$1</I18n.ComponentInterpolator></div>'); | ||
}); | ||
it('doesn\'t use the empty components\'s key as the placeholder name if it\'s not a literal', function() { | ||
expect(subject('<div translate="yes">Create <input key={something} /> new accounts</div>')) | ||
.toEqual('<div><I18n.ComponentInterpolator string={I18n.t("Create %{input_key_something} new accounts", { "input_key_something": "%{input_key_something}" })} input_key_something={<input key={something} />}>$1</I18n.ComponentInterpolator></div>'); | ||
}); | ||
it('creates placeholders for translate="no" components', function() { | ||
@@ -62,0 +82,0 @@ expect(subject('<div translate="yes">to create an alert, type <code translate="no">alert()</code></div>')) |
{ | ||
"name": "react-i18nliner", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"description": "i18n made simple", | ||
@@ -5,0 +5,0 @@ "main": "main.js", |
@@ -86,10 +86,13 @@ var recast = require('recast'); | ||
if (node.type !== "JSXElement") return; | ||
var attributes = node.openingElement.attributes; | ||
var index = findAttributeIndex(attribute, attributes); | ||
var value; | ||
if (index >= 0) { | ||
value = attributes[index].value.value; | ||
if (shouldSpliceFn && shouldSpliceFn(value)) { | ||
attributes.splice(index, 1); | ||
} | ||
if (index < 0) return; | ||
var value = attributes[index].value; | ||
if (attributes[index].value.type !== "Literal") return; | ||
value = value.value; | ||
if (shouldSpliceFn && shouldSpliceFn(value)) { | ||
attributes.splice(index, 1); | ||
} | ||
@@ -99,3 +102,4 @@ return value; | ||
var extractTranslateAttribute = findAttribute.bind(null, "translate"); | ||
var findTranslateAttribute = findAttribute.bind(null, "translate"); | ||
var findKeyAttribute = findAttribute.bind(null, "key"); | ||
@@ -131,3 +135,3 @@ | ||
var tagName = node.openingElement && node.openingElement.name.name; | ||
var translateAttr = extractTranslateAttribute(node, shouldSpliceTranslateAttr); | ||
var translateAttr = findTranslateAttribute(node, shouldSpliceTranslateAttr); | ||
if (translateAttr) { | ||
@@ -247,12 +251,21 @@ return translateAttr === "yes"; | ||
var placeholderBaseFor = function(node) { | ||
var source = recast.print(node).code; | ||
var baseString = source.replace(/<\/[^>]+>/g, '') | ||
.replace(/([A-Z]+)?([A-Z])/g, '$1 $2') | ||
.replace(/this\.((state|props)\.)/g, ''); | ||
if (node.type === "JSXExpressionContainer") | ||
node = node.expression; | ||
if (hasNonJSXDescendants(node)) { | ||
baseString = baseString.replace(/<\w+[^>]*>/, ''); | ||
var baseString; | ||
if (node.type === "JSXElement") | ||
baseString = findKeyAttribute(node); | ||
if (!baseString) { | ||
var source = recast.print(node).code; | ||
baseString = source.replace(/<\/[^>]+>/g, '') | ||
.replace(/this\.((state|props)\.)/g, ''); | ||
if (hasNonJSXDescendants(node)) { | ||
baseString = baseString.replace(/<\w+[^>]*>/, ''); | ||
} | ||
} | ||
return baseString.toLowerCase() | ||
return baseString.replace(/([A-Z]+)?([A-Z])/g, '$1 $2') | ||
.toLowerCase() | ||
.replace(/[^a-z0-9]/g, ' ') | ||
@@ -284,3 +297,3 @@ .trim() | ||
part = wrappedStringFor(child, wrappers, placeholders); | ||
} else if (findNestedJSXExpressions(child).length === 1 || !translatable) { | ||
} else if (findNestedJSXExpressions(child).length === 1 || !translatable || findKeyAttribute(child)) { | ||
part = placeholderStringFor(child, placeholders); | ||
@@ -287,0 +300,0 @@ } else { |
@@ -22,7 +22,10 @@ # react-i18nliner | ||
`translate="yes"` attribute on any element/component that needs to be | ||
localized. | ||
localized. Seriously. | ||
Best of all, you don't need to maintain translation files anymore; | ||
I18nliner will do it for you. | ||
And because the default translation is inline, it will be used as a | ||
fallback if a translation is missing or hasn't happened yet. | ||
Best of all, you don't need to maintain separate translation files | ||
anymore; I18nliner will do it for you. | ||
## How does it work? | ||
@@ -65,7 +68,24 @@ | ||
By default, placeholder keys will be inferred from the content, so a | ||
translator would see `"Create %{input} keys"` and `"Welcome back, | ||
%{user_name}"`. For complicated expressions, these placeholder keys can | ||
get a bit long/gnarly. Having to retranslate strings that "changed" just | ||
because you refactored some code is terrible, so you can use keys to | ||
be a bit more explicit: | ||
```html | ||
<label translate="yes"> | ||
Create <input key="numAccounts" onChange={this.addAccounts} /> new | ||
accounts | ||
</label> | ||
``` | ||
In this case the extracted string would just be `"Create %{num_accounts} | ||
new accounts"` | ||
### Wrappers | ||
Translators won't see any markup; it will be replaced with a simple wrapper | ||
notation. In this example, the extracted string would be `"That is *not* | ||
the right answer"`: | ||
Translators won't see any components or markup; they will be replaced with | ||
a simple wrapper notation. In this example, the extracted string would be | ||
`"That is *not* the right answer"`: | ||
@@ -82,3 +102,4 @@ ```html | ||
`Your Account"` will also be preprocessed, since it is a valid | ||
[translatable attribute](http://www.w3.org/TR/html5/dom.html#the-translate-attribute). | ||
[translatable attribute](http://www.w3.org/TR/html5/dom.html#the-translate-attribute) | ||
within a translated element. | ||
@@ -91,3 +112,2 @@ ```html | ||
## Installation | ||
@@ -94,0 +114,0 @@ |
37804
656
288