Refactor l10n code. Remove use of react-intl. (#2975)

Strings from .dtd files are now accessible from Zotero.getMessage
as the eventual move to Fluent would remove their distinction.
This commit is contained in:
Adomas Ven 2023-01-17 22:59:19 +02:00 committed by GitHub
parent 1f721feab7
commit 0ffe3122c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 151 additions and 182 deletions

View file

@ -25,7 +25,6 @@
const React = require('react'); const React = require('react');
const ReactDOM = require('react-dom'); const ReactDOM = require('react-dom');
const { IntlProvider } = require('react-intl');
const LibraryTree = require('./libraryTree'); const LibraryTree = require('./libraryTree');
const VirtualizedTable = require('components/virtualized-table'); const VirtualizedTable = require('components/virtualized-table');
const { TreeSelectionStub } = VirtualizedTable; const { TreeSelectionStub } = VirtualizedTable;
@ -42,9 +41,7 @@ var CollectionTree = class CollectionTree extends LibraryTree {
var ref; var ref;
opts.domEl = domEl; opts.domEl = domEl;
let elem = ( let elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<CollectionTree ref={c => ref = c } {...opts} /> <CollectionTree ref={c => ref = c } {...opts} />
</IntlProvider>
); );
await new Promise(resolve => ReactDOM.render(elem, domEl, resolve)); await new Promise(resolve => ReactDOM.render(elem, domEl, resolve));

View file

@ -29,7 +29,6 @@ import React, { memo } from 'react';
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import cx from 'classnames'; import cx from 'classnames';
import { IntlProvider, FormattedMessage } from "react-intl";
// This is a quick reimplementation of the annotation for use in the conflict resolution window. // This is a quick reimplementation of the annotation for use in the conflict resolution window.
// We'll want to replace this with a single component shared between the PDF reader and the rest // We'll want to replace this with a single component shared between the PDF reader and the rest
@ -40,10 +39,6 @@ function AnnotationBox({ data }) {
}; };
return ( return (
<IntlProvider
locale={ Zotero.locale }
messages={ Zotero.Intl.strings }
>
<div className="AnnotationBox"> <div className="AnnotationBox">
<div className="title">{Zotero.getString('itemTypes.annotation')}</div> <div className="title">{Zotero.getString('itemTypes.annotation')}</div>
<div className="container"> <div className="container">
@ -64,7 +59,6 @@ function AnnotationBox({ data }) {
: ''} : ''}
</div> </div>
</div> </div>
</IntlProvider>
); );
} }

View file

@ -27,7 +27,6 @@
const React = require('react') const React = require('react')
const { PureComponent, createElement: create } = React const { PureComponent, createElement: create } = React
const { injectIntl } = require('react-intl')
const { IconDownChevron } = require('./icons') const { IconDownChevron } = require('./icons')
const cx = require('classnames') const cx = require('classnames')
const { const {
@ -59,19 +58,19 @@ class Button extends PureComponent {
} }
get text() { get text() {
const { intl, text } = this.props const { text } = this.props;
return text ? return text ?
intl.formatMessage({ id: text }) : Zotero.getString(text) :
null null;
} }
get title() { get title() {
const { intl, title } = this.props const { title } = this.props;
return title ? return title ?
intl.formatMessage({ id: title }) : Zotero.getString(title) :
null null;
} }
get menuMarker() { get menuMarker() {
@ -159,5 +158,5 @@ class Button extends PureComponent {
module.exports = { module.exports = {
ButtonGroup, ButtonGroup,
Button: injectIntl(Button) Button
} }

View file

@ -29,7 +29,6 @@ import React, { memo } from 'react';
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import cx from 'classnames'; import cx from 'classnames';
import { IntlProvider } from "react-intl";
function CreateParent({ loading, item, toggleAccept }) { function CreateParent({ loading, item, toggleAccept }) {
// When the input has/does not have characters toggle the accept button on the dialog // When the input has/does not have characters toggle the accept button on the dialog
@ -43,10 +42,6 @@ function CreateParent({ loading, item, toggleAccept }) {
}; };
return ( return (
<IntlProvider
locale={ Zotero.locale }
messages={ Zotero.Intl.strings }
>
<div className="create-parent-container"> <div className="create-parent-container">
<span className="title"> <span className="title">
{ item.attachmentFilename } { item.attachmentFilename }
@ -67,7 +62,6 @@ function CreateParent({ loading, item, toggleAccept }) {
</div> </div>
</div> </div>
</div> </div>
</IntlProvider>
); );
} }

View file

@ -25,7 +25,6 @@
import React, { memo, useCallback, useEffect, useRef } from 'react'; import React, { memo, useCallback, useEffect, useRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { getDOMElement } from 'components/icons'; import { getDOMElement } from 'components/icons';
import { IntlProvider } from 'react-intl';
import VirtualizedTable, { renderCell } from 'components/virtualized-table'; import VirtualizedTable, { renderCell } from 'components/virtualized-table';
import { noop } from './utils'; import { noop } from './utils';
@ -101,7 +100,6 @@ const ProgressQueueTable = ({ onActivate = noop, progressQueue }) => {
}, []); // eslint-disable-line react-hooks/exhaustive-deps }, []); // eslint-disable-line react-hooks/exhaustive-deps
return ( return (
<IntlProvider locale={ Zotero.locale } messages={ Zotero.Intl.strings }>
<VirtualizedTable <VirtualizedTable
getRowCount={ getRowCount } getRowCount={ getRowCount }
ref={ treeRef } ref={ treeRef }
@ -111,7 +109,6 @@ const ProgressQueueTable = ({ onActivate = noop, progressQueue }) => {
columns={ tableColumns } columns={ tableColumns }
onActivate={ onActivate } onActivate={ onActivate }
/> />
</IntlProvider>
); );
}; };

View file

@ -25,7 +25,6 @@
const React = require('react'); const React = require('react');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const { FormattedMessage } = require('react-intl');
var { Collection } = require('react-virtualized'); var { Collection } = require('react-virtualized');
// See also .tag-selector-item in _tag-selector.scss // See also .tag-selector-item in _tag-selector.scss
@ -191,14 +190,14 @@ class TagList extends React.PureComponent {
if (!this.props.loaded) { if (!this.props.loaded) {
tagList = ( tagList = (
<div className="tag-selector-message"> <div className="tag-selector-message">
<FormattedMessage id="zotero.tagSelector.loadingTags" /> {Zotero.getString('zotero.tagSelector.loadingTags')}
</div> </div>
); );
} }
else if (tagCount == 0) { else if (tagCount == 0) {
tagList = ( tagList = (
<div className="tag-selector-message"> <div className="tag-selector-message">
<FormattedMessage id="zotero.tagSelector.noTagsToDisplay" /> {Zotero.getString('zotero.tagSelector.noTagsToDisplay')}
</div> </div>
); );
} }

View file

@ -30,7 +30,6 @@ const PropTypes = require('prop-types');
const cx = require('classnames'); const cx = require('classnames');
const WindowedList = require('./windowed-list'); const WindowedList = require('./windowed-list');
const Draggable = require('./draggable'); const Draggable = require('./draggable');
const { injectIntl } = require('react-intl');
const { IconDownChevron, getDOMElement } = require('components/icons'); const { IconDownChevron, getDOMElement } = require('components/icons');
const TYPING_TIMEOUT = 1000; const TYPING_TIMEOUT = 1000;
@ -1636,7 +1635,7 @@ function makeRowRenderer(getRowData) {
function formatColumnName(column) { function formatColumnName(column) {
if (column.label in Zotero.Intl.strings) { if (column.label in Zotero.Intl.strings) {
return Zotero.Intl.strings[column.label]; return Zotero.getString(column.label);
} }
else if (/^[^\s]+\w\.\w[^\s]+$/.test(column.label)) { else if (/^[^\s]+\w\.\w[^\s]+$/.test(column.label)) {
try { try {
@ -1652,7 +1651,7 @@ function formatColumnName(column) {
return column.label; return column.label;
} }
module.exports = injectIntl(VirtualizedTable, { forwardRef: true }); module.exports = VirtualizedTable;
module.exports.TreeSelection = TreeSelection; module.exports.TreeSelection = TreeSelection;
module.exports.TreeSelectionStub = TreeSelectionStub; module.exports.TreeSelectionStub = TreeSelectionStub;
module.exports.renderCell = renderCell; module.exports.renderCell = renderCell;

View file

@ -31,7 +31,6 @@
const React = require('react'); const React = require('react');
const ReactDOM = require('react-dom'); const ReactDOM = require('react-dom');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const { IntlProvider } = require('react-intl');
const TagSelector = require('components/tagSelector.js'); const TagSelector = require('components/tagSelector.js');
const defaults = { const defaults = {
tagColors: new Map(), tagColors: new Map(),
@ -762,9 +761,7 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
static init(domEl, opts) { static init(domEl, opts) {
var ref; var ref;
let elem = ( let elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<TagSelectorContainer ref={c => ref = c } {...opts} /> <TagSelectorContainer ref={c => ref = c } {...opts} />
</IntlProvider>
); );
ReactDOM.render(elem, domEl); ReactDOM.render(elem, domEl);
ref.domEl = domEl; ref.domEl = domEl;

View file

@ -937,13 +937,13 @@ var ZoteroContextPane = new function () {
// Info tab // Info tab
var tabInfo = document.createElement('tab'); var tabInfo = document.createElement('tab');
tabInfo.setAttribute('label', Zotero.Intl.strings['zotero.tabs.info.label']); tabInfo.setAttribute('label', Zotero.getString('zotero.tabs.info.label'));
// Tags tab // Tags tab
var tabTags = document.createElement('tab'); var tabTags = document.createElement('tab');
tabTags.setAttribute('label', Zotero.Intl.strings['zotero.tabs.tags.label']); tabTags.setAttribute('label', Zotero.getString('zotero.tabs.tags.label'));
// Related tab // Related tab
var tabRelated = document.createElement('tab'); var tabRelated = document.createElement('tab');
tabRelated.setAttribute('label', Zotero.Intl.strings['zotero.tabs.related.label']); tabRelated.setAttribute('label', Zotero.getString('zotero.tabs.related.label'));
tabs.append(tabInfo, tabTags, tabRelated); tabs.append(tabInfo, tabTags, tabRelated);

View file

@ -27,7 +27,6 @@ const { noop, getDragTargetOrient } = require("components/utils");
const PropTypes = require("prop-types"); const PropTypes = require("prop-types");
const React = require('react'); const React = require('react');
const ReactDOM = require('react-dom'); const ReactDOM = require('react-dom');
const { IntlProvider } = require('react-intl');
const LibraryTree = require('./libraryTree'); const LibraryTree = require('./libraryTree');
const VirtualizedTable = require('components/virtualized-table'); const VirtualizedTable = require('components/virtualized-table');
const { renderCell, formatColumnName } = VirtualizedTable; const { renderCell, formatColumnName } = VirtualizedTable;
@ -49,9 +48,7 @@ var ItemTree = class ItemTree extends LibraryTree {
var ref; var ref;
opts.domEl = domEl; opts.domEl = domEl;
let elem = ( let elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<ItemTree ref={c => ref = c } {...opts} /> <ItemTree ref={c => ref = c } {...opts} />
</IntlProvider>
); );
await new Promise(resolve => ReactDOM.render(elem, domEl, resolve)); await new Promise(resolve => ReactDOM.render(elem, domEl, resolve));
@ -3730,7 +3727,7 @@ var ItemTree = class ItemTree extends LibraryTree {
// Restore Default Column Order // Restore Default Column Order
// //
let menuitem = doc.createElementNS(ns, 'menuitem'); let menuitem = doc.createElementNS(ns, 'menuitem');
menuitem.setAttribute('label', Zotero.Intl.strings['zotero.items.restoreColumnOrder.label']); menuitem.setAttribute('label', Zotero.getString('zotero.items.restoreColumnOrder.label'));
menuitem.setAttribute('anonid', prefix + 'restore-order'); menuitem.setAttribute('anonid', prefix + 'restore-order');
menuitem.addEventListener('command', () => this.tree._columns.restoreDefaultOrder()); menuitem.addEventListener('command', () => this.tree._columns.restoreDefaultOrder());
menupopup.appendChild(menuitem); menupopup.appendChild(menuitem);

View file

@ -24,7 +24,6 @@
*/ */
import VirtualizedTable from 'components/virtualized-table'; import VirtualizedTable from 'components/virtualized-table';
const { IntlProvider } = require('react-intl');
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
@ -41,7 +40,6 @@ function init() {
engines = Zotero.LocateManager.getEngines(); engines = Zotero.LocateManager.getEngines();
const domEl = document.querySelector('#locateManager-tree'); const domEl = document.querySelector('#locateManager-tree');
let elem = ( let elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<VirtualizedTable <VirtualizedTable
getRowCount={() => engines.length} getRowCount={() => engines.length}
id="locateManager-table" id="locateManager-table"
@ -54,7 +52,6 @@ function init() {
getRowString={index => getRowData(index).name} getRowString={index => getRowData(index).name}
onActivate={handleActivate} onActivate={handleActivate}
/> />
</IntlProvider>
); );
return new Promise(resolve => ReactDOM.render(elem, domEl, resolve)); return new Promise(resolve => ReactDOM.render(elem, domEl, resolve));
} }

View file

@ -30,7 +30,6 @@ import FilePicker from 'zotero/modules/filePicker';
var React = require('react'); var React = require('react');
var ReactDOM = require('react-dom'); var ReactDOM = require('react-dom');
var VirtualizedTable = require('components/virtualized-table'); var VirtualizedTable = require('components/virtualized-table');
var { IntlProvider } = require('react-intl');
var { makeRowRenderer } = VirtualizedTable; var { makeRowRenderer } = VirtualizedTable;
Zotero_Preferences.Cite = { Zotero_Preferences.Cite = {
@ -118,7 +117,6 @@ Zotero_Preferences.Cite = {
} }
}; };
let elem = ( let elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<VirtualizedTable <VirtualizedTable
getRowCount={() => this.styles.length} getRowCount={() => this.styles.length}
id="styleManager-table" id="styleManager-table"
@ -133,7 +131,6 @@ Zotero_Preferences.Cite = {
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
getRowString={index => this.styles[index].title} getRowString={index => this.styles[index].title}
/> />
</IntlProvider>
); );
await new Promise(resolve => ReactDOM.render(elem, document.getElementById("styleManager"), resolve)); await new Promise(resolve => ReactDOM.render(elem, document.getElementById("styleManager"), resolve));
} }

View file

@ -28,7 +28,6 @@
var React = require('react'); var React = require('react');
var ReactDOM = require('react-dom'); var ReactDOM = require('react-dom');
var VirtualizedTable = require('components/virtualized-table'); var VirtualizedTable = require('components/virtualized-table');
var { IntlProvider } = require('react-intl');
var { makeRowRenderer } = VirtualizedTable; var { makeRowRenderer } = VirtualizedTable;
Zotero_Preferences.Export = { Zotero_Preferences.Export = {
@ -492,7 +491,6 @@ Zotero_Preferences.Export = {
}; };
let elem = ( let elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<VirtualizedTable <VirtualizedTable
getRowCount={() => this._rows.length} getRowCount={() => this._rows.length}
id="quickCopy-siteSettings-table" id="quickCopy-siteSettings-table"
@ -507,7 +505,6 @@ Zotero_Preferences.Export = {
getRowString={index => this._rows[index].domain} getRowString={index => this._rows[index].domain}
onActivate={(event, indices) => Zotero_Preferences.Export.showQuickCopySiteEditor()} onActivate={(event, indices) => Zotero_Preferences.Export.showQuickCopySiteEditor()}
/> />
</IntlProvider>
); );
await new Promise(resolve => ReactDOM.render(elem, document.getElementById("quickCopy-siteSettings"), resolve)); await new Promise(resolve => ReactDOM.render(elem, document.getElementById("quickCopy-siteSettings"), resolve));
} else { } else {

View file

@ -32,7 +32,6 @@ var React = require('react');
var ReactDOM = require('react-dom'); var ReactDOM = require('react-dom');
var VirtualizedTable = require('components/virtualized-table'); var VirtualizedTable = require('components/virtualized-table');
var { getDOMElement } = require('components/icons'); var { getDOMElement } = require('components/icons');
var { IntlProvider } = require('react-intl');
var { renderCell } = VirtualizedTable; var { renderCell } = VirtualizedTable;
Zotero_Preferences.Sync = { Zotero_Preferences.Sync = {
@ -319,7 +318,6 @@ Zotero_Preferences.Sync = {
} }
}; };
let elem = ( let elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<VirtualizedTable <VirtualizedTable
getRowCount={() => this._rows.length} getRowCount={() => this._rows.length}
id="librariesToSync-table" id="librariesToSync-table"
@ -332,7 +330,6 @@ Zotero_Preferences.Sync = {
disableFontSizeScaling={true} disableFontSizeScaling={true}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
/> />
</IntlProvider>
); );
ReactDOM.render(elem, document.getElementById("libraries-to-sync-tree")); ReactDOM.render(elem, document.getElementById("libraries-to-sync-tree"));

View file

@ -288,15 +288,15 @@
<ul id="sync-reset-list"> <ul id="sync-reset-list">
<!--<li> <!--<li>
<p>&zotero.preferences.sync.reset.restoreFromServer;</p> <p>&zotero.preferences.sync.reset.restoreFromOnlineLibrary;</p>
<p>&zotero.preferences.sync.reset.restoreFromServer.desc;</p> <p>&zotero.preferences.sync.reset.restoreFromOnlineLibrary.desc;</p>
</li>--> </li>-->
<li id="restore-to-server"> <li id="restore-to-server">
<label> <label>
<input name="sync-reset-radiogroup" value="restore-to-server" type="radio"/> <input name="sync-reset-radiogroup" value="restore-to-server" type="radio"/>
<span class="sync-reset-option-name">&zotero.preferences.sync.reset.restoreToServer;</span> <span class="sync-reset-option-name">&zotero.preferences.sync.reset.restoreToOnlineLibrary;</span>
<span class="sync-reset-option-desc">&zotero.preferences.sync.reset.restoreToServer.desc;</span> <span class="sync-reset-option-desc">&zotero.preferences.sync.reset.restoreToOnlineLibrary.desc;</span>
</label> </label>
</li> </li>

View file

@ -31,7 +31,6 @@ import FilePicker from 'zotero/modules/filePicker';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import VirtualizedTable from 'components/virtualized-table'; import VirtualizedTable from 'components/virtualized-table';
import { IntlProvider } from 'react-intl';
import { getDOMElement } from 'components/icons'; import { getDOMElement } from 'components/icons';
/** /**
@ -51,9 +50,9 @@ var Zotero_RTFScan = new function() {
var ids = 0; var ids = 0;
var tree; var tree;
this._rows = [ this._rows = [
{ id: 'unmapped', rtf: Zotero.Intl.strings['zotero.rtfScan.unmappedCitations.label'], collapsed: false }, { id: 'unmapped', rtf: Zotero.getString('zotero.rtfScan.unmappedCitations.label'), collapsed: false },
{ id: 'ambiguous', rtf: Zotero.Intl.strings['zotero.rtfScan.ambiguousCitations.label'], collapsed: false }, { id: 'ambiguous', rtf: Zotero.getString('zotero.rtfScan.ambiguousCitations.label'), collapsed: false },
{ id: 'mapped', rtf: Zotero.Intl.strings['zotero.rtfScan.mappedCitations.label'], collapsed: false }, { id: 'mapped', rtf: Zotero.getString('zotero.rtfScan.mappedCitations.label'), collapsed: false },
]; ];
this._rowMap = {}; this._rowMap = {};
this._rows.forEach((row, index) => this._rowMap[row.id] = index); this._rows.forEach((row, index) => this._rowMap[row.id] = index);
@ -388,9 +387,9 @@ var Zotero_RTFScan = new function() {
document.documentElement.currentPage = document.getElementById('intro-page'); document.documentElement.currentPage = document.getElementById('intro-page');
this._rows = [ this._rows = [
{ id: 'unmapped', rtf: Zotero.Intl.strings['zotero.rtfScan.unmappedCitations.label'], collapsed: false }, { id: 'unmapped', rtf: Zotero.getString('zotero.rtfScan.unmappedCitations.label'), collapsed: false },
{ id: 'ambiguous', rtf: Zotero.Intl.strings['zotero.rtfScan.ambiguousCitations.label'], collapsed: false }, { id: 'ambiguous', rtf: Zotero.getString('zotero.rtfScan.ambiguousCitations.label'), collapsed: false },
{ id: 'mapped', rtf: Zotero.Intl.strings['zotero.rtfScan.mappedCitations.label'], collapsed: false }, { id: 'mapped', rtf: Zotero.getString('zotero.rtfScan.mappedCitations.label'), collapsed: false },
]; ];
this._rowMap = {}; this._rowMap = {};
this._rows.forEach((row, index) => this._rowMap[row.id] = index); this._rows.forEach((row, index) => this._rowMap[row.id] = index);
@ -768,7 +767,6 @@ var Zotero_RTFScan = new function() {
this._initCitationTree = function () { this._initCitationTree = function () {
const domEl = document.querySelector('#tree'); const domEl = document.querySelector('#tree');
const elem = ( const elem = (
<IntlProvider locale={Zotero.locale} messages={Zotero.Intl.strings}>
<VirtualizedTable <VirtualizedTable
getRowCount={() => this._rows.length} getRowCount={() => this._rows.length}
id="rtfScan-table" id="rtfScan-table"
@ -778,7 +776,6 @@ var Zotero_RTFScan = new function() {
columns={columns} columns={columns}
disableFontSizeScaling={true} disableFontSizeScaling={true}
/> />
</IntlProvider>
); );
return new Promise(resolve => ReactDOM.render(elem, domEl, resolve)); return new Promise(resolve => ReactDOM.render(elem, domEl, resolve));
}; };

View file

@ -55,7 +55,8 @@ Zotero.Intl = new function () {
Components.utils.import("resource://gre/modules/PluralForm.jsm"); Components.utils.import("resource://gre/modules/PluralForm.jsm");
bundle = Services.strings.createBundle('chrome://zotero/locale/zotero.properties'); // Exposed for tests
this._bundle = bundle = Services.strings.createBundle('chrome://zotero/locale/zotero.properties');
intlProps = Services.strings.createBundle('chrome://zotero/locale/mozilla/intl.properties'); intlProps = Services.strings.createBundle('chrome://zotero/locale/mozilla/intl.properties');
[pluralFormGet, pluralFormNumForms] = PluralForm.makeGetter(parseInt(getIntlProp('pluralRule', 1))); [pluralFormGet, pluralFormNumForms] = PluralForm.makeGetter(parseInt(getIntlProp('pluralRule', 1)));
@ -105,6 +106,9 @@ Zotero.Intl = new function () {
} }
l10n = bundle.formatStringFromName(name, params, params.length); l10n = bundle.formatStringFromName(name, params, params.length);
} }
else if (this.strings[name]) {
return this.strings[name];
}
else { else {
l10n = bundle.GetStringFromName(name); l10n = bundle.GetStringFromName(name);
} }

View file

@ -76,10 +76,10 @@
<!ENTITY zotero.preferences.sync.reset.warning3 " for more information."> <!ENTITY zotero.preferences.sync.reset.warning3 " for more information.">
<!ENTITY zotero.preferences.sync.reset.resetDataSyncHistory "Reset Data Sync History"> <!ENTITY zotero.preferences.sync.reset.resetDataSyncHistory "Reset Data Sync History">
<!ENTITY zotero.preferences.sync.reset.resetDataSyncHistory.desc "Merge local data with remote data, ignoring sync history"> <!ENTITY zotero.preferences.sync.reset.resetDataSyncHistory.desc "Merge local data with remote data, ignoring sync history">
<!ENTITY zotero.preferences.sync.reset.restoreFromServer "Restore from Online Library"> <!ENTITY zotero.preferences.sync.reset.restoreFromOnlineLibrary "Restore from Online Library">
<!ENTITY zotero.preferences.sync.reset.restoreFromServer.desc "Overwrite local Zotero data with data from the online library."> <!ENTITY zotero.preferences.sync.reset.restoreFromOnlineLibrary.desc "Overwrite local Zotero data with data from the online library.">
<!ENTITY zotero.preferences.sync.reset.restoreToServer "Replace Online Library"> <!ENTITY zotero.preferences.sync.reset.restoreToOnlineLibrary "Replace Online Library">
<!ENTITY zotero.preferences.sync.reset.restoreToServer.desc "Overwrite online library with local Zotero data"> <!ENTITY zotero.preferences.sync.reset.restoreToOnlineLibrary.desc "Overwrite online library with local Zotero data">
<!ENTITY zotero.preferences.sync.reset.resetFileSyncHistory "Reset File Sync History"> <!ENTITY zotero.preferences.sync.reset.resetFileSyncHistory "Reset File Sync History">
<!ENTITY zotero.preferences.sync.reset.resetFileSyncHistory.desc "Compare all attachment files with the storage service"> <!ENTITY zotero.preferences.sync.reset.resetFileSyncHistory.desc "Compare all attachment files with the storage service">
<!ENTITY zotero.preferences.sync.reset "Reset"> <!ENTITY zotero.preferences.sync.reset "Reset">

View file

@ -23,4 +23,11 @@ describe("Zotero.Intl", function() {
assert.equal(Zotero.localeCompare("_Abcd", "Abcd"), -1); assert.equal(Zotero.localeCompare("_Abcd", "Abcd"), -1);
}); });
}); });
it("there should not be duplicate string keys in .dtd and .properties files", function () {
let dtdStrings = Object.keys(Zotero.Intl.strings);
for (let key of dtdStrings) {
assert.throws(() => Zotero.Intl._bundle.GetStringFromName(key));
}
});
}); });