mirror of https://github.com/vector-im/riot-web
Merge branch 'develop' into luke/groups-are-communities
commit
c3f143acc3
|
@ -28,11 +28,13 @@
|
||||||
"test"
|
"test"
|
||||||
],
|
],
|
||||||
"bin": {
|
"bin": {
|
||||||
"reskindex": "scripts/reskindex.js"
|
"reskindex": "scripts/reskindex.js",
|
||||||
|
"matrix-gen-i18n": "scripts/gen-i18n.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"reskindex": "node scripts/reskindex.js -h header",
|
"reskindex": "node scripts/reskindex.js -h header",
|
||||||
"reskindex:watch": "node scripts/reskindex.js -h header -w",
|
"reskindex:watch": "node scripts/reskindex.js -h header -w",
|
||||||
|
"i18n": "matrix-gen-i18n",
|
||||||
"build": "npm run reskindex && babel src -d lib --source-maps --copy-files",
|
"build": "npm run reskindex && babel src -d lib --source-maps --copy-files",
|
||||||
"build:watch": "babel src -w -d lib --source-maps --copy-files",
|
"build:watch": "babel src -w -d lib --source-maps --copy-files",
|
||||||
"emoji-data-strip": "node scripts/emoji-data-strip.js",
|
"emoji-data-strip": "node scripts/emoji-data-strip.js",
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2017 New Vector Ltd
|
Copyright 2017 New Vector Ltd
|
||||||
|
|
||||||
|
@ -34,6 +36,13 @@ const TRANSLATIONS_FUNCS = ['_t', '_td', '_tJsx'];
|
||||||
|
|
||||||
const INPUT_TRANSLATIONS_FILE = 'src/i18n/strings/en_EN.json';
|
const INPUT_TRANSLATIONS_FILE = 'src/i18n/strings/en_EN.json';
|
||||||
|
|
||||||
|
// NB. The sync version of walk is broken for single files so we walk
|
||||||
|
// all of res rather than just res/home.html.
|
||||||
|
// https://git.daplie.com/Daplie/node-walk/merge_requests/1 fixes it,
|
||||||
|
// or if we get bored waiting for it to be merged, we could switch
|
||||||
|
// to a project that's actively maintained.
|
||||||
|
const SEARCH_PATHS = ['src', 'res'];
|
||||||
|
|
||||||
const FLOW_PARSER_OPTS = {
|
const FLOW_PARSER_OPTS = {
|
||||||
esproposal_class_instance_fields: true,
|
esproposal_class_instance_fields: true,
|
||||||
esproposal_class_static_fields: true,
|
esproposal_class_static_fields: true,
|
||||||
|
@ -64,7 +73,7 @@ function getTKey(arg) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTranslations(file) {
|
function getTranslationsJs(file) {
|
||||||
const tree = flowParser.parse(fs.readFileSync(file, { encoding: 'utf8' }), FLOW_PARSER_OPTS);
|
const tree = flowParser.parse(fs.readFileSync(file, { encoding: 'utf8' }), FLOW_PARSER_OPTS);
|
||||||
|
|
||||||
const trs = new Set();
|
const trs = new Set();
|
||||||
|
@ -106,6 +115,20 @@ function getTranslations(file) {
|
||||||
return trs;
|
return trs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTranslationsOther(file) {
|
||||||
|
const contents = fs.readFileSync(file, { encoding: 'utf8' });
|
||||||
|
|
||||||
|
const trs = new Set();
|
||||||
|
|
||||||
|
// Taken from riot-web src/components/structures/HomePage.js
|
||||||
|
const translationsRegex = /_t\(['"]([\s\S]*?)['"]\)/mg;
|
||||||
|
let matches;
|
||||||
|
while (matches = translationsRegex.exec(contents)) {
|
||||||
|
trs.add(matches[1]);
|
||||||
|
}
|
||||||
|
return trs;
|
||||||
|
}
|
||||||
|
|
||||||
// gather en_EN plural strings from the input translations file:
|
// gather en_EN plural strings from the input translations file:
|
||||||
// the en_EN strings are all in the source with the exception of
|
// the en_EN strings are all in the source with the exception of
|
||||||
// pluralised strings, which we need to pull in from elsewhere.
|
// pluralised strings, which we need to pull in from elsewhere.
|
||||||
|
@ -123,20 +146,32 @@ for (const key of Object.keys(inputTranslationsRaw)) {
|
||||||
|
|
||||||
const translatables = new Set();
|
const translatables = new Set();
|
||||||
|
|
||||||
walk.walkSync("src", {
|
const walkOpts = {
|
||||||
listeners: {
|
listeners: {
|
||||||
file: function(root, fileStats, next) {
|
file: function(root, fileStats, next) {
|
||||||
if (!fileStats.name.endsWith('.js')) return;
|
|
||||||
|
|
||||||
const fullPath = path.join(root, fileStats.name);
|
const fullPath = path.join(root, fileStats.name);
|
||||||
const trs = getTranslations(fullPath);
|
|
||||||
|
let ltrs;
|
||||||
|
if (fileStats.name.endsWith('.js')) {
|
||||||
|
trs = getTranslationsJs(fullPath);
|
||||||
|
} else if (fileStats.name.endsWith('.html')) {
|
||||||
|
trs = getTranslationsOther(fullPath);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.log(`${fullPath} (${trs.size} strings)`);
|
console.log(`${fullPath} (${trs.size} strings)`);
|
||||||
for (const tr of trs.values()) {
|
for (const tr of trs.values()) {
|
||||||
translatables.add(tr);
|
translatables.add(tr);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
for (const path of SEARCH_PATHS) {
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
walk.walkSync(path, walkOpts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const trObj = {};
|
const trObj = {};
|
||||||
for (const tr of translatables) {
|
for (const tr of translatables) {
|
||||||
|
|
|
@ -490,15 +490,15 @@ export default React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNameChange: function(e) {
|
_onNameChange: function(value) {
|
||||||
const newProfileForm = Object.assign(this.state.profileForm, { name: e.target.value });
|
const newProfileForm = Object.assign(this.state.profileForm, { name: value });
|
||||||
this.setState({
|
this.setState({
|
||||||
profileForm: newProfileForm,
|
profileForm: newProfileForm,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_onShortDescChange: function(e) {
|
_onShortDescChange: function(value) {
|
||||||
const newProfileForm = Object.assign(this.state.profileForm, { short_description: e.target.value });
|
const newProfileForm = Object.assign(this.state.profileForm, { short_description: value });
|
||||||
this.setState({
|
this.setState({
|
||||||
profileForm: newProfileForm,
|
profileForm: newProfileForm,
|
||||||
});
|
});
|
||||||
|
@ -878,18 +878,28 @@ export default React.createClass({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
nameNode = <input type="text"
|
|
||||||
value={this.state.profileForm.name}
|
const EditableText = sdk.getComponent("elements.EditableText");
|
||||||
onChange={this._onNameChange}
|
|
||||||
placeholder={_t('Community Name')}
|
nameNode = <EditableText ref="nameEditor"
|
||||||
tabIndex="1"
|
className="mx_GroupView_editable"
|
||||||
/>;
|
placeholderClassName="mx_GroupView_placeholder"
|
||||||
shortDescNode = <input type="text"
|
placeholder={_t('Community Name')}
|
||||||
value={this.state.profileForm.short_description}
|
blurToCancel={false}
|
||||||
onChange={this._onShortDescChange}
|
initialValue={this.state.profileForm.name}
|
||||||
placeholder={_t('Description')}
|
onValueChanged={this._onNameChange}
|
||||||
tabIndex="2"
|
tabIndex="1"
|
||||||
/>;
|
dir="auto" />;
|
||||||
|
|
||||||
|
shortDescNode = <EditableText ref="descriptionEditor"
|
||||||
|
className="mx_GroupView_editable"
|
||||||
|
placeholderClassName="mx_GroupView_placeholder"
|
||||||
|
placeholder={_t("Description")}
|
||||||
|
blurToCancel={false}
|
||||||
|
initialValue={this.state.profileForm.short_description}
|
||||||
|
onValueChanged={this._onShortDescChange}
|
||||||
|
tabIndex="2"
|
||||||
|
dir="auto" />;
|
||||||
rightButtons.push(
|
rightButtons.push(
|
||||||
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
|
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
|
||||||
onClick={this._onSaveClick} key="_saveButton"
|
onClick={this._onSaveClick} key="_saveButton"
|
||||||
|
@ -911,17 +921,17 @@ export default React.createClass({
|
||||||
width={48} height={48}
|
width={48} height={48}
|
||||||
/>;
|
/>;
|
||||||
if (summary.profile && summary.profile.name) {
|
if (summary.profile && summary.profile.name) {
|
||||||
nameNode = <div>
|
nameNode = <div onClick={this._onEditClick}>
|
||||||
<span>{ summary.profile.name }</span>
|
<span>{ summary.profile.name }</span>
|
||||||
<span className="mx_GroupView_header_groupid">
|
<span className="mx_GroupView_header_groupid">
|
||||||
({ this.props.groupId })
|
({ this.props.groupId })
|
||||||
</span>
|
</span>
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
nameNode = <span>{ this.props.groupId }</span>;
|
nameNode = <span onClick={this._onEditClick}>{ this.props.groupId }</span>;
|
||||||
}
|
}
|
||||||
if (summary.profile && summary.profile.short_description) {
|
if (summary.profile && summary.profile.short_description) {
|
||||||
shortDescNode = <span>{ summary.profile.short_description }</span>;
|
shortDescNode = <span onClick={this._onEditClick}>{ summary.profile.short_description }</span>;
|
||||||
}
|
}
|
||||||
rightButtons.push(
|
rightButtons.push(
|
||||||
<AccessibleButton className="mx_GroupHeader_button"
|
<AccessibleButton className="mx_GroupHeader_button"
|
||||||
|
|
Loading…
Reference in New Issue