diff --git a/functional-test/pom.xml b/functional-test/pom.xml index b11876d325..c072575196 100644 --- a/functional-test/pom.xml +++ b/functional-test/pom.xml @@ -4,7 +4,7 @@ org.zanata server - 3.4.3-SNAPSHOT + 3.5.0-SNAPSHOT functional-test @@ -36,6 +36,8 @@ jdbc:mysql://localhost:${mysql.port}/${ds.database}?characterEncoding=UTF-8 com.mysql.jdbc.Driver + 15.0 + zanata-test-${project.version} @@ -66,6 +68,36 @@ 2552 + + + + org.apache.httpcomponents + httpclient + 4.3.3 + + + org.apache.httpcomponents + httpcore + 4.3.2 + + + org.apache.httpcomponents + httpmime + 4.3.3 + + + xerces + xercesImpl + 2.11.0 + + + net.sourceforge.cssparser + cssparser + 0.9.13 + + + + org.assertj @@ -164,12 +196,6 @@ org.hibernate hibernate-entitymanager ${hibernate.version} - - - org.javassist - javassist - - ${hibernate.scope} @@ -208,6 +234,12 @@ 0.3 + + org.codehaus.jackson + jackson-mapper-asl + + + org.zanata @@ -217,6 +249,16 @@ org.jboss.resteasy resteasy-jaxrs + + + javassist + javassist + + + javax.annotation + jsr250-api + + org.zanata @@ -307,7 +349,6 @@ org.javassist javassist - test org.hibernate @@ -318,6 +359,10 @@ org.apache.solr solr-core + + jakarta-regexp + jakarta-regexp + org.apache.commons commons-io @@ -352,7 +397,7 @@ com.google.code.findbugs - jsr305 + annotations @@ -632,9 +677,12 @@ listener - org.zanata.util.ScreenshotEnabledTestRunListener + org.zanata.util.ScreenshotEnabledTestRunListener,org.zanata.util.FeatureInventoryRecorder + + ${project.build.directory}/feature-inventory + @@ -685,6 +733,11 @@ **/pom.xml + + src/test/resources/feature-inventory + false + ${project.build.directory}/feature-inventory + @@ -721,7 +774,6 @@ maven-dependency-plugin - true mysql:mysql-connector-java org.apache.solr:solr-core @@ -737,6 +789,21 @@ + + maven-enforcer-plugin + + + + + + jakarta-regexp:jakarta-regexp + + true + + + + + maven-surefire-plugin diff --git a/functional-test/src/main/java/org/zanata/page/BasePage.java b/functional-test/src/main/java/org/zanata/page/BasePage.java index ba9422a0c5..1222941b4f 100644 --- a/functional-test/src/main/java/org/zanata/page/BasePage.java +++ b/functional-test/src/main/java/org/zanata/page/BasePage.java @@ -30,6 +30,7 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.ExpectedConditions; import org.zanata.page.account.RegisterPage; import org.zanata.page.account.SignInPage; import org.zanata.page.administration.AdministrationPage; @@ -88,11 +89,13 @@ public DashboardBasePage goToMyDashboard() { } public ProjectsPage goToProjects() { - clickNavMenuItem(projectsLink); + clickNavMenuItem(getDriver().findElement(By.id("projects_link"))); return new ProjectsPage(getDriver()); } private void clickNavMenuItem(final WebElement menuItem) { + scrollToTop(); + slightPause(); if (!menuItem.isDisplayed()) { // screen is too small the menu become dropdown getDriver().findElement(By.id("nav-main")) @@ -104,6 +107,8 @@ public boolean apply(WebDriver input) { return menuItem.isDisplayed(); } }); + // The notifications can sometimes get in the way + waitForTenSec().until(ExpectedConditions.elementToBeClickable(menuItem)); menuItem.click(); } @@ -114,7 +119,7 @@ public VersionGroupsPage goToGroups() { public GlossaryPage goToGlossary() { // Dynamically find the link, as it is not present for every user - getDriver().findElement(By.id("glossary_link")).click(); + clickNavMenuItem(getDriver().findElement(By.id("glossary_link"))); return new GlossaryPage(getDriver()); } @@ -153,6 +158,7 @@ public String loggedInAs() { } public HomePage logout() { + scrollIntoView(userAvatar); userAvatar.click(); clickLinkAfterAnimation(BY_SIGN_OUT); @@ -218,7 +224,8 @@ public void clickLinkAfterAnimation(WebElement element) { } public HelpPage goToHelp() { - getDriver().findElement(By.id("help_link")).click(); + WebElement help_link = getDriver().findElement(By.id("help_link")); + clickNavMenuItem(help_link); return new HelpPage(getDriver()); } @@ -279,12 +286,13 @@ public boolean apply(WebDriver input) { waitForPageSilence(); boolean clicked = false; try { + scrollIntoView(tab); if (tab.isDisplayed() && tab.isEnabled()) { tab.click(); clicked = true; } } catch(WebDriverException wde) { - return clicked; + return false; } return clicked; } @@ -296,4 +304,8 @@ public String getHtmlSource(WebElement webElement) { "return arguments[0].innerHTML;", webElement); } + public void clickElement(By findby) { + scrollIntoView(getDriver().findElement(findby)); + getDriver().findElement(findby).click(); + } } diff --git a/functional-test/src/main/java/org/zanata/page/CorePage.java b/functional-test/src/main/java/org/zanata/page/CorePage.java index 36738f2086..f0e19de206 100644 --- a/functional-test/src/main/java/org/zanata/page/CorePage.java +++ b/functional-test/src/main/java/org/zanata/page/CorePage.java @@ -27,6 +27,7 @@ import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -60,6 +61,7 @@ public String getTitle() { } public HomePage goToHomePage() { + scrollToTop(); homeLink.click(); return new HomePage(getDriver()); } @@ -209,4 +211,13 @@ public void slightPause() { log.warn("Pause was interrupted"); } } + + public void scrollIntoView(WebElement targetElement) { + ((JavascriptExecutor) getDriver()).executeScript( + "arguments[0].scrollIntoView(true);", targetElement); + } + + public void scrollToTop() { + ((JavascriptExecutor) getDriver()).executeScript("scroll(0, 0);"); + } } diff --git a/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java b/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java index a58c9b39ab..0be44ebafe 100644 --- a/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java +++ b/functional-test/src/main/java/org/zanata/page/account/RegisterPage.java @@ -38,8 +38,19 @@ */ public class RegisterPage extends CorePage { - public final String USERNAMEVALIDATIONERROR = "Between 3 and 20 lowercase "+ - "letters, numbers and underscores only"; + public static final String USERNAME_VALIDATION_ERROR = + "Between 3 and 20 lowercase letters, numbers and underscores only"; + + public static final String USERNAME_UNAVAILABLE_ERROR = + "This username is not available"; + + public static final String MALFORMED_EMAIL_ERROR = + "not a well-formed email address"; + + public static final String REQUIRED_FIELD_ERROR = "value is required"; + + public static final String USERNAME_LENGTH_ERROR = + "size must be between 3 and 20"; @FindBy(id = "loginForm:name") private WebElement nameField; @@ -108,7 +119,7 @@ public RegisterPage clearFields() { /* * Pass in a map of strings, to be entered into the registration fields. - * Fields: name, email, username, password, confirmpassword, captcha + * Fields: name, email, username, password, confirmpassword */ public RegisterPage setFields(Map fields) { return clearFields() @@ -129,4 +140,26 @@ public WebElement apply(WebDriver driver) { return getErrors(); } + public String getPageTitle() { + return getDriver().findElement(By.className("heading--sub")) + .getText(); + } + + public SignInPage goToSignIn() { + getDriver().findElement(By.linkText("Log In")).click(); + return new SignInPage(getDriver()); + } + + public RegisterPage clickPasswordShowToggle() { + getDriver().findElement(By.className("js-form-password-toggle")).click(); + return new RegisterPage(getDriver()); + } + + public String getPassword() { + return passwordField.getAttribute("value"); + } + + public String getPasswordFieldType() { + return passwordField.getAttribute("type"); + } } diff --git a/functional-test/src/main/java/org/zanata/page/account/SignInPage.java b/functional-test/src/main/java/org/zanata/page/account/SignInPage.java index f560ea4b21..883d5a5717 100644 --- a/functional-test/src/main/java/org/zanata/page/account/SignInPage.java +++ b/functional-test/src/main/java/org/zanata/page/account/SignInPage.java @@ -32,6 +32,9 @@ @Slf4j public class SignInPage extends CorePage { + + public static final String LOGIN_FAILED_ERROR = "Login failed"; + @FindBy(id = "loginForm:username") private WebElement usernameField; @@ -78,4 +81,13 @@ public ResetPasswordPage goToResetPassword() { return new ResetPasswordPage(getDriver()); } + public RegisterPage goToRegister() { + getDriver().findElement(By.linkText("Sign Up")).click(); + return new RegisterPage(getDriver()); + } + + public String getPageTitle() { + return getDriver().findElement(By.className("heading--sub")) + .getText(); + } } diff --git a/functional-test/src/main/java/org/zanata/page/administration/AddLanguagePage.java b/functional-test/src/main/java/org/zanata/page/administration/AddLanguagePage.java index eee4085103..fa7c161dad 100644 --- a/functional-test/src/main/java/org/zanata/page/administration/AddLanguagePage.java +++ b/functional-test/src/main/java/org/zanata/page/administration/AddLanguagePage.java @@ -54,6 +54,7 @@ public AddLanguagePage(final WebDriver driver) { public AddLanguagePage inputLanguage(String language) { languageInput.sendKeys(language); defocus(); + waitForPageSilence(); return this; } diff --git a/functional-test/src/main/java/org/zanata/page/administration/AdministrationPage.java b/functional-test/src/main/java/org/zanata/page/administration/AdministrationPage.java index 3969fa79a1..69ec6dec33 100644 --- a/functional-test/src/main/java/org/zanata/page/administration/AdministrationPage.java +++ b/functional-test/src/main/java/org/zanata/page/administration/AdministrationPage.java @@ -34,6 +34,9 @@ public class AdministrationPage extends BasePage { private final By MANAGE_SEARCH_LINK = By.id("Admin_Manage_search_home"); + private final By MANAGE_ROLES_ASSIGN_LINK = + By.id("Admin_Role_Assignment_Rules_home"); + public AdministrationPage(WebDriver driver) { super(driver); } @@ -57,4 +60,9 @@ public ManageSearchPage goToManageSeachPage() { clickLinkAfterAnimation(MANAGE_SEARCH_LINK); return new ManageSearchPage(getDriver()); } + + public RoleAssignmentsPage goToManageRoleAssignments() { + clickLinkAfterAnimation(MANAGE_ROLES_ASSIGN_LINK); + return new RoleAssignmentsPage(getDriver()); + } } diff --git a/functional-test/src/main/java/org/zanata/page/administration/EditHomeContentPage.java b/functional-test/src/main/java/org/zanata/page/administration/EditHomeContentPage.java index ec17b0c678..e90c560387 100644 --- a/functional-test/src/main/java/org/zanata/page/administration/EditHomeContentPage.java +++ b/functional-test/src/main/java/org/zanata/page/administration/EditHomeContentPage.java @@ -34,9 +34,6 @@ */ public class EditHomeContentPage extends BasePage { - @FindBy(className = "html.CSS1Compat") - private WebElement textEdit; - @FindBy(id = "homeContentForm:update") private WebElement updateButton; @@ -48,14 +45,26 @@ public EditHomeContentPage(final WebDriver driver) { } public EditHomeContentPage enterText(String text) { - waitForTenSec().until(new Function() { + // Switch to the CKEditor frame + getDriver().switchTo().frame(waitForTenSec().until(new Function() { + @Override + public WebElement apply(WebDriver driver) { + return getDriver().findElement( + By.id("cke_contents_homeContentForm:homeContent:inp")) + .findElement(By.tagName("iframe")); + } + })); + + WebElement textEdit = waitForTenSec().until(new Function() { @Override public WebElement apply(WebDriver driver) { - return getDriver().findElement(By.className("html.CSS1Compat")); + System.out.println(getDriver().findElements(By.tagName("body")).size()); + return getDriver().findElement(By.tagName("body")); } }); - textEdit.click(); textEdit.sendKeys(text); + // Switch back! + getDriver().switchTo().defaultContent(); return new EditHomeContentPage(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/administration/EditRoleAssignmentPage.java b/functional-test/src/main/java/org/zanata/page/administration/EditRoleAssignmentPage.java new file mode 100644 index 0000000000..f1b5c44106 --- /dev/null +++ b/functional-test/src/main/java/org/zanata/page/administration/EditRoleAssignmentPage.java @@ -0,0 +1,49 @@ +package org.zanata.page.administration; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; +import org.zanata.page.BasePage; + +/** + * @author Damian Jansen djansen@redhat.com + */ +public class EditRoleAssignmentPage extends BasePage { + + public EditRoleAssignmentPage(WebDriver driver) { + super(driver); + } + + public EditRoleAssignmentPage selectPolicy(String policy) { + Select policySelect = new Select(getDriver().findElement( + By.id("projectForm:policyNameField:policyName"))); + policySelect.selectByValue(policy); + return new EditRoleAssignmentPage(getDriver()); + } + + public EditRoleAssignmentPage enterIdentityPattern(String pattern) { + WebElement patternField = getDriver().findElement( + By.id("projectForm:identityPatternField:identityPattern")); + patternField.clear(); + patternField.sendKeys(pattern); + return new EditRoleAssignmentPage(getDriver()); + } + + public EditRoleAssignmentPage selectRole(String role) { + Select roleSelect = new Select(getDriver().findElement( + By.id("projectForm:roleField:roles"))); + roleSelect.selectByValue(role); + return new EditRoleAssignmentPage(getDriver()); + } + + public EditRoleAssignmentPage saveRoleAssignment() { + getDriver().findElement(By.id("projectForm:save")).click(); + return new EditRoleAssignmentPage(getDriver()); + } + + public RoleAssignmentsPage cancelEditRoleAssignment() { + getDriver().findElement(By.id("projectForm:cancel")).click(); + return new RoleAssignmentsPage(getDriver()); + } +} diff --git a/functional-test/src/main/java/org/zanata/page/administration/ManageUserAccountPage.java b/functional-test/src/main/java/org/zanata/page/administration/ManageUserAccountPage.java index 671debc730..36703f4d7f 100644 --- a/functional-test/src/main/java/org/zanata/page/administration/ManageUserAccountPage.java +++ b/functional-test/src/main/java/org/zanata/page/administration/ManageUserAccountPage.java @@ -38,6 +38,9 @@ @Slf4j public class ManageUserAccountPage extends BasePage { + + public static String PASSWORD_ERROR = "Passwords do not match"; + @FindBy(id = "userdetailForm:passwordField:password") private WebElement passwordField; @@ -68,21 +71,6 @@ public ManageUserAccountPage(WebDriver driver) { roleMap.put("user", "4"); } - public ManageUserAccountPage enterUsername(final String username) { - waitForTenSec().until(new Predicate() { - @Override - public boolean apply(WebDriver input) { - WebElement usernameField = input.findElement(usernameBy); - usernameField.clear(); - usernameField.sendKeys(username); - return input.findElement(usernameBy).getAttribute("value") - .equals(username); - } - }); - - return new ManageUserAccountPage(getDriver()); - } - public ManageUserAccountPage enterPassword(String password) { passwordField.sendKeys(password); return new ManageUserAccountPage(getDriver()); @@ -118,22 +106,14 @@ public ManageUserPage saveUser() { return new ManageUserPage(getDriver()); } + public ManageUserAccountPage saveUserExpectFailure() { + saveButton.click(); + return new ManageUserAccountPage(getDriver()); + } + public ManageUserPage cancelEditUser() { cancelButton.click(); return new ManageUserPage(getDriver()); } - public ManageUserAccountPage clearFields() { - waitForTenSec().until(new Predicate() { - @Override - public boolean apply(WebDriver input) { - input.findElement(usernameBy).clear(); - return input.findElement(usernameBy).getAttribute("value") - .isEmpty(); - } - }); - passwordField.clear(); - passwordConfirmField.clear(); - return new ManageUserAccountPage(getDriver()); - } } diff --git a/functional-test/src/main/java/org/zanata/page/administration/ManageUserPage.java b/functional-test/src/main/java/org/zanata/page/administration/ManageUserPage.java index 4ba140f62d..0684fd1064 100644 --- a/functional-test/src/main/java/org/zanata/page/administration/ManageUserPage.java +++ b/functional-test/src/main/java/org/zanata/page/administration/ManageUserPage.java @@ -40,7 +40,7 @@ */ public class ManageUserPage extends BasePage { public static final int USERNAME_COLUMN = 0; - @FindBy(id = "usermanagerForm:threads") + @FindBy(id = "usermanagerForm:userList") private WebElement userTable; private By userTableBy = By.id("usermanagerForm:threads"); @@ -54,7 +54,8 @@ public ManageUserAccountPage editUserAccount(String username) { List cells = userRow.getCells(); WebElement editCell = cells.get(cells.size() - 1); WebElement editButton = - editCell.findElement(By.xpath(".//input[@value='Edit']")); + editCell.findElement(By + .xpath(".//button[contains(text(), 'Edit')]")); editButton.click(); return new ManageUserAccountPage(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/administration/RoleAssignmentsPage.java b/functional-test/src/main/java/org/zanata/page/administration/RoleAssignmentsPage.java new file mode 100644 index 0000000000..30fa4963b2 --- /dev/null +++ b/functional-test/src/main/java/org/zanata/page/administration/RoleAssignmentsPage.java @@ -0,0 +1,35 @@ +package org.zanata.page.administration; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.zanata.page.BasePage; +import org.zanata.util.TableRow; +import org.zanata.util.WebElementUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Damian Jansen djansen@redhat.com + */ +public class RoleAssignmentsPage extends BasePage { + + public RoleAssignmentsPage(WebDriver driver) { + super(driver); + } + + public EditRoleAssignmentPage clickCreateNew() { + getDriver().findElement(By.linkText("New Rule")).click(); + return new EditRoleAssignmentPage(getDriver()); + } + + public List getRulesByPattern() { + List names = new ArrayList(); + List tableRows = WebElementUtil.getTableRows(getDriver(), + By.tagName("table")); + for (TableRow tableRow : tableRows) { + names.add(tableRow.getCells().get(1).getText()); + } + return names; + } +} diff --git a/functional-test/src/main/java/org/zanata/page/administration/TranslationMemoryPage.java b/functional-test/src/main/java/org/zanata/page/administration/TranslationMemoryPage.java index b84e636d90..677953ea9b 100644 --- a/functional-test/src/main/java/org/zanata/page/administration/TranslationMemoryPage.java +++ b/functional-test/src/main/java/org/zanata/page/administration/TranslationMemoryPage.java @@ -44,6 +44,10 @@ public class TranslationMemoryPage extends BasePage { private static final int EXPORT_COLUMN = 5; private static final int ACTIONS_COLUMN = 6; + public static final String ID_UNAVAILABLE = "This Id is not available"; + public static final String UPLOAD_ERROR = + "There was an error uploading the file"; + @FindBy(id = "createTmLink") private WebElement createTmLink; diff --git a/functional-test/src/main/java/org/zanata/page/dashboard/DashboardActivityTab.java b/functional-test/src/main/java/org/zanata/page/dashboard/DashboardActivityTab.java index 8e153eae7c..16f0d09707 100644 --- a/functional-test/src/main/java/org/zanata/page/dashboard/DashboardActivityTab.java +++ b/functional-test/src/main/java/org/zanata/page/dashboard/DashboardActivityTab.java @@ -23,9 +23,10 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.ExpectedCondition; import org.zanata.util.WebElementUtil; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; @@ -48,13 +49,26 @@ public List getMyActivityList() { return new ArrayList(); } - public void clickMoreActivity() { + /** + * Click on the activity list's "More Activity element". + * @return true, if there is more activity available. False otherwise. + */ + public boolean clickMoreActivity() { WebElement moreActivity = getMoreActivityElement(); + final int activityListOrigSize = getMyActivityList().size(); if (moreActivity != null) { moreActivity.click(); WebElementUtil.waitForTenSeconds(getDriver()).until( - ExpectedConditions.invisibilityOfElementLocated(By - .className("loader__spinner"))); + new ExpectedCondition() { + @Nullable + @Override + public Object apply(@Nullable WebDriver input) { + return getMyActivityList().size() > activityListOrigSize; + } + }); + return true; + } else { + return false; } } diff --git a/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java b/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java index 550e04ec69..5f95b019b0 100644 --- a/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java +++ b/functional-test/src/main/java/org/zanata/page/dashboard/DashboardBasePage.java @@ -62,6 +62,13 @@ public class DashboardBasePage extends BasePage { @FindBy(id = "activity-month_tab") private WebElement thisMonthsActivityTab; + public final static String EMAIL_SENT = + "You will soon receive an email with a link to activate your " + + "email account change."; + + public final static String PASSWORD_UPDATE_SUCCESS = + "Your password has been successfully changed."; + public DashboardBasePage(final WebDriver driver) { super(driver); } @@ -116,18 +123,13 @@ public DashboardClientTab goToSettingsClientTab() { return new DashboardClientTab(getDriver()); } - public void waitForLoaderFinished() { - slightPause(); + public void waitForUsernameChanged(final String current) { waitForTenSec().until(new Predicate() { @Override public boolean apply(WebDriver input) { - return !isLoaderVisible(); + return !getUserFullName().equals(current); } }); } - public boolean isLoaderVisible() { - return getDriver().findElement(By.className("loader__spinner")) - .isDisplayed(); - } } diff --git a/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardAccountTab.java b/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardAccountTab.java index 18b5d2d875..c83f342a69 100644 --- a/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardAccountTab.java +++ b/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardAccountTab.java @@ -30,6 +30,17 @@ */ public class DashboardAccountTab extends DashboardBasePage { + public static final String INCORRECT_OLD_PASSWORD_ERROR = + "Old password is incorrect, please check and try again."; + + public static final String FIELD_EMPTY_ERROR = "may not be empty"; + + public static final String PASSWORD_LENGTH_ERROR = + "size must be between 6 and 20"; + + public static final String EMAIL_TAKEN_ERROR = + "This email address is already taken"; + @FindBy(id = "email-update-form:emailField:email") private WebElement emailField; diff --git a/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardClientTab.java b/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardClientTab.java index fac6b16051..63716ba9ff 100644 --- a/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardClientTab.java +++ b/functional-test/src/main/java/org/zanata/page/dashboard/dashboardsettings/DashboardClientTab.java @@ -20,6 +20,7 @@ */ package org.zanata.page.dashboard.dashboardsettings; +import com.google.common.base.Predicate; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -56,4 +57,13 @@ public String getApiKey() { public String getConfigurationDetails() { return configurationTextArea.getText(); } + + public void waitForApiKeyChanged(final String current) { + waitForTenSec().until(new Predicate() { + @Override + public boolean apply(WebDriver input) { + return !getApiKey().equals(current); + } + }); + } } diff --git a/functional-test/src/main/java/org/zanata/page/groups/CreateVersionGroupPage.java b/functional-test/src/main/java/org/zanata/page/groups/CreateVersionGroupPage.java index e766c18727..2b1ca764de 100644 --- a/functional-test/src/main/java/org/zanata/page/groups/CreateVersionGroupPage.java +++ b/functional-test/src/main/java/org/zanata/page/groups/CreateVersionGroupPage.java @@ -21,6 +21,13 @@ @Slf4j public class CreateVersionGroupPage extends BasePage { + public final static String LENGTH_ERROR = + "value must be shorter than or equal to 100 characters"; + + public final static String VALIDATION_ERROR = + "must start and end with letter or number, and contain only " + + "letters, numbers, periods, underscores and hyphens."; + @FindBy(id = "group-form:descriptionField:description") private WebElement groupDescriptionField; diff --git a/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java b/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java index b09d3d77ef..93bb7d5deb 100644 --- a/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java +++ b/functional-test/src/main/java/org/zanata/page/groups/VersionGroupPage.java @@ -38,6 +38,11 @@ public VersionGroupPage(final WebDriver driver) { private final By newVersionListBy = By .id("settings-projects-form:newVersionField:newVersionItems"); + public String getGroupName() { + return getDriver().findElement(By.id("group-info")) + .findElement(By.tagName("h1")).getText(); + } + public List searchProject(final String projectName, final int expectedResultNum) { projectSearchField.sendKeys(projectName); @@ -144,22 +149,22 @@ public boolean apply(WebDriver driver) { } public VersionGroupPage clickLanguagesTab() { - clickWhenTabEnabled(getDriver().findElement(By.id("languages"))); + clickWhenTabEnabled(getDriver().findElement(By.id("languages_tab"))); return new VersionGroupPage(getDriver()); } public VersionGroupPage clickProjectsTab() { - clickWhenTabEnabled(getDriver().findElement(By.id("projects"))); + clickWhenTabEnabled(getDriver().findElement(By.id("projects_tab"))); return new VersionGroupPage(getDriver()); } public VersionGroupPage clickMaintainersTab() { - clickWhenTabEnabled(getDriver().findElement(By.id("maintainers"))); + clickWhenTabEnabled(getDriver().findElement(By.id("maintainers_tab"))); return new VersionGroupPage(getDriver()); } public VersionGroupPage clickSettingsTab() { - clickWhenTabEnabled(getDriver().findElement(By.id("settings"))); + clickWhenTabEnabled(getDriver().findElement(By.id("settings_tab"))); return new VersionGroupPage(getDriver()); } @@ -204,23 +209,23 @@ public VersionGroupPage enterProjectVersion(String projectVersion) { } public VersionGroupPage selectProjectVersion(final String searchEntry) { - WebElement searchItem = waitForTenSec().until( - new Function() { - @Override - public WebElement apply(WebDriver driver) { - List items = WebElementUtil - .getSearchAutocompleteResults(driver, - "settings-projects-form", - "versionAutocomplete"); - for (WebElement item : items) { - if (item.getText().equals(searchEntry)) { - return item; + waitForTenSec().until( + new Predicate() { + @Override + public boolean apply(WebDriver driver) { + List items = WebElementUtil + .getSearchAutocompleteResults(driver, + "settings-projects-form", + "versionAutocomplete"); + for (WebElement item : items) { + if (item.getText().equals(searchEntry)) { + item.click(); + return true; + } + } + return false; } - } - return null; - } - }); - searchItem.click(); + }); return new VersionGroupPage(getDriver()); } diff --git a/functional-test/src/main/java/org/zanata/page/projects/ProjectVersionsPage.java b/functional-test/src/main/java/org/zanata/page/projects/ProjectVersionsPage.java index 88e66cf36e..16c024c858 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/ProjectVersionsPage.java +++ b/functional-test/src/main/java/org/zanata/page/projects/ProjectVersionsPage.java @@ -20,12 +20,10 @@ */ package org.zanata.page.projects; -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; +import java.util.List; + import lombok.extern.slf4j.Slf4j; + import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; @@ -35,7 +33,7 @@ import org.zanata.page.projectversion.VersionLanguagesPage; import org.zanata.util.WebElementUtil; -import java.util.List; +import com.google.common.base.Predicate; /** * @author Damian Jansen @@ -63,41 +61,29 @@ public CreateVersionPage clickCreateVersionLink() { } public VersionLanguagesPage gotoVersion(final String versionId) { - return refreshPageUntil(this, - new Function() { - @Override - public VersionLanguagesPage apply(WebDriver input) { - WebElement versionForm = - getDriver().findElement(By.id("versions_form")); - - List versionLinks = - versionForm.findElement( - By.className("list--stats")) - .findElements(By.tagName("li")); - - log.info("found {} active versions", - versionLinks.size()); - - Optional found = - Iterables.tryFind(versionLinks, - new Predicate() { - @Override - public boolean apply( - WebElement input) { - return input - .findElement( - By.className("list__title")) - .getText() - .contains(versionId); - } - }); - - Preconditions.checkState(found.isPresent(), versionId - + " not found"); - found.get().click(); - return new VersionLanguagesPage(getDriver()); - }; - }); + waitForTenSec().until(new Predicate() { + @Override + public boolean apply(WebDriver input) { + List versionLinks = getDriver() + .findElement(By.id("versions_form")) + .findElement(By.className("list--stats")) + .findElements(By.tagName("li")); + boolean clicked = false; + for (WebElement links : versionLinks) { + // The Translate Options menu can get picked up here + for (WebElement link : links.findElements(By.tagName("a"))) { + if (link.getText().contains(versionId)) { + link.click(); + clicked = true; + break; + } + } + if (clicked) break; + } + return clicked; + } + }); + return new VersionLanguagesPage(getDriver()); } public List getVersions() { diff --git a/functional-test/src/main/java/org/zanata/page/projects/ProjectsPage.java b/functional-test/src/main/java/org/zanata/page/projects/ProjectsPage.java index 68a2994233..7bdc661cd5 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/ProjectsPage.java +++ b/functional-test/src/main/java/org/zanata/page/projects/ProjectsPage.java @@ -68,7 +68,7 @@ public ProjectVersionsPage apply(WebDriver input) { PROJECT_NAME_COLUMN)); WebElement link = table.findElement(By.linkText(projectName)); link.click(); - return new ProjectVersionsPage(input); + return new ProjectVersionsPage(getDriver()); } }); } diff --git a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectAboutTab.java b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectAboutTab.java index b225d5cdc5..0d3589f5f7 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectAboutTab.java +++ b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectAboutTab.java @@ -56,7 +56,7 @@ public String getAboutText() { } public ProjectAboutTab pressSave() { - getDriver().findElement(By.linkText("Save notes")).click(); + clickElement(By.linkText("Save notes")); return new ProjectAboutTab(getDriver()); } } diff --git a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java index 6ef62b675d..18809e3897 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java +++ b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectGeneralTab.java @@ -57,9 +57,6 @@ public class ProjectGeneralTab extends ProjectBasePage { @FindBy(id = "settings-general-form:repoField:repo") private WebElement repoField; - @FindBy(id = "settings-general-form:button-update-settings") - private WebElement updateButton; - public ProjectGeneralTab(WebDriver driver) { super(driver); } @@ -107,7 +104,9 @@ public ProjectGeneralTab enterDescription(String projectDescription) { */ public ProjectGeneralTab selectProjectType(String projectType) { assert getProjectTypes().containsKey(projectType); - getProjectTypes().get(projectType).click(); + WebElement projectTypeButton = getProjectTypes().get(projectType); + scrollIntoView(projectTypeButton); + projectTypeButton.click(); return new ProjectGeneralTab(getDriver()); } @@ -158,9 +157,7 @@ public boolean isArchiveButtonAvailable() { * @return new Project General Settings page */ public ProjectGeneralTab archiveProject() { - getDriver().findElement( - By.id("settings-general-form:button-archive-project")) - .click(); + clickElement(By.id("settings-general-form:button-archive-project")); return new ProjectGeneralTab(getDriver()); } @@ -169,9 +166,7 @@ public ProjectGeneralTab archiveProject() { * @return new Project General Settings page */ public ProjectGeneralTab unarchiveProject() { - getDriver().findElement( - By.id("settings-general-form:button-unarchive-project")) - .click(); + clickElement(By.id("settings-general-form:button-unarchive-project")); return new ProjectGeneralTab(getDriver()); } @@ -180,9 +175,7 @@ public ProjectGeneralTab unarchiveProject() { * @return new Project General Settings page */ public ProjectGeneralTab lockProject() { - getDriver().findElement( - By.id("settings-general-form:button-lock-project")) - .click(); + clickElement(By.id("settings-general-form:button-lock-project")); return new ProjectGeneralTab(getDriver()); } @@ -191,9 +184,7 @@ public ProjectGeneralTab lockProject() { * @return new Project General Settings page */ public ProjectGeneralTab unlockProject() { - getDriver().findElement( - By.id("settings-general-form:button-unlock-project")) - .click(); + clickElement(By.id("settings-general-form:button-unlock-project")); return new ProjectGeneralTab(getDriver()); } @@ -224,7 +215,14 @@ public ProjectGeneralTab enterRepository(String repo) { * @return new Project General Settings page */ public ProjectGeneralTab updateProject() { - clickAndCheckErrors(updateButton); + scrollIntoView(updateButton()); + clickAndCheckErrors(updateButton()); return new ProjectGeneralTab(getDriver()); } + + private WebElement updateButton() { + return getDriver().findElement( + By.id("settings-general-form:button-update-settings")); + } + } diff --git a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectLanguagesTab.java b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectLanguagesTab.java index fcb1b09261..477a2d40f3 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectLanguagesTab.java +++ b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectLanguagesTab.java @@ -66,7 +66,21 @@ public String apply(WebElement li) { private List getEnabledLocaleListElement() { return getDriver().findElement(By.id("settings-languages-form")) - .findElements(By.xpath(".//ul/li[@class='reveal--list-item']")); + .findElement(By.className("list--slat")) + .findElements(By.className("reveal--list-item")); + } + + public ProjectLanguagesTab waitForLocaleListVisible() { + waitForTenSec().until(new Predicate() { + @Override + public boolean apply(WebDriver driver) { + return getDriver() + .findElement(By.id("settings-languages-form")) + .findElement(By.className("list--slat")) + .isDisplayed(); + } + }); + return new ProjectLanguagesTab(getDriver()); } /** @@ -88,28 +102,27 @@ public ProjectLanguagesTab enterSearchLanguage(String languageQuery) { * @return new language settings, anticipating the language has been added. */ public ProjectLanguagesTab addLanguage(final String localeId) { - waitForTenSec().until(new Function>() { + waitForTenSec().until(new Predicate() { @Override - public List apply(WebDriver driver) { - return WebElementUtil.getSearchAutocompleteResults(driver, - "settings-languages-form", "languageAutocomplete"); + public boolean apply(WebDriver driver) { + List searchResults = + WebElementUtil.getSearchAutocompleteResults( + getDriver(), + "settings-languages-form", + "languageAutocomplete"); + + boolean clickedLocale = false; + for (WebElement searchResult : searchResults) { + if (searchResult.getText().contains(localeId)) { + searchResult.click(); + clickedLocale = true; + break; + } + } + return clickedLocale; } }); - List searchResults = - WebElementUtil.getSearchAutocompleteResults(getDriver(), - "settings-languages-form", "languageAutocomplete"); - - boolean clickedLocale = false; - for (WebElement searchResult : searchResults) { - if (searchResult.getText().contains(localeId)) { - searchResult.click(); - clickedLocale = true; - break; - } - } - Preconditions.checkState(clickedLocale, "can not find locale - %s", - localeId); refreshPageUntil(this, new Predicate() { @Override diff --git a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectPermissionsTab.java b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectPermissionsTab.java index 91a71fb142..8efc3340f2 100644 --- a/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectPermissionsTab.java +++ b/functional-test/src/main/java/org/zanata/page/projects/projectsettings/ProjectPermissionsTab.java @@ -31,6 +31,7 @@ import org.zanata.page.projects.ProjectBasePage; import org.zanata.util.WebElementUtil; +import javax.annotation.Nullable; import java.util.List; /** @@ -50,60 +51,61 @@ public ProjectPermissionsTab enterSearchMaintainer( return new ProjectPermissionsTab(getDriver()); } - public ProjectPermissionsTab selectSearchMaintainer(String maintainer) { - List searchResults = waitForTenSec() - .until(new Function>() { + public ProjectPermissionsTab selectSearchMaintainer(final String maintainer) { + waitForTenSec() + .until(new Predicate() { @Override - public List apply(WebDriver driver) { - return WebElementUtil.getSearchAutocompleteResults( - driver, - "settings-permissions-form", - "maintainerAutocomplete"); + public boolean apply(WebDriver driver) { + List searchResults = + WebElementUtil.getSearchAutocompleteResults( + driver, + "settings-permissions-form", + "maintainerAutocomplete"); + boolean clickedUser = false; + for (WebElement searchResult : searchResults) { + if (searchResult.getText().contains(maintainer)) { + searchResult.click(); + clickedUser = true; + break; + } + } + return clickedUser; } }); - - boolean clickedUser = false; - for (WebElement searchResult : searchResults) { - if (searchResult.getText().contains(maintainer)) { - searchResult.click(); - clickedUser = true; - break; - } - } - Preconditions.checkState(clickedUser, "Can not find username - %s", - maintainer); - return new ProjectPermissionsTab(getDriver()); } public ProjectPermissionsTab clickRemoveOn(String maintainer) { - for (WebElement maintainersLi : getSettingsMaintainersElement()) { - String displayedUsername = getUsername(maintainersLi); - if (displayedUsername.equals(maintainer)) { - maintainersLi.findElement(By.tagName("a")).click(); - break; - } - } + getMaintainerElementFromList(maintainer).click(); return new ProjectPermissionsTab(getDriver()); } public ProjectBasePage clickRemoveOnSelf(String maintainer) { - for (WebElement maintainersLi : getSettingsMaintainersElement()) { - String displayedUsername = getUsername(maintainersLi); - if (displayedUsername.equals(maintainer)) { - maintainersLi.findElement(By.tagName("a")).click(); - break; - } - } + getMaintainerElementFromList(maintainer).click(); return new ProjectBasePage(getDriver()); } private String getUsername(WebElement maintainersLi) { return maintainersLi - .findElement(By.xpath(".//span[@class='txt--meta']")).getText() + .findElement(By.className("txt--meta")).getText() .replace("@", ""); } + private WebElement getMaintainerElementFromList(final String maintainer) { + return waitForTenSec().until(new Function() { + @Override + public WebElement apply(WebDriver input) { + for (WebElement maintainersLi : getSettingsMaintainersElement()) { + String displayedUsername = getUsername(maintainersLi); + if (displayedUsername.equals(maintainer)) { + return maintainersLi.findElement(By.tagName("a")); + } + } + return null; + } + }); + } + public ProjectPermissionsTab waitForMaintainersContains( final String username) { return refreshPageUntil(this, new Predicate() { @@ -125,13 +127,14 @@ public boolean apply(WebDriver driver) { } public List getSettingsMaintainersElement() { - return getDriver().findElement(By.id("settings-permissions-form")) - .findElements(By.xpath(".//ul/li[@class='reveal--list-item']")); + return getDriver() + .findElement(By.id("settings-permissions-form")) + .findElement(By.id("maintainers-list")) + .findElements(By.className("reveal--list-item")); } public List getSettingsMaintainersList() { List items = getSettingsMaintainersElement(); - List rows = Lists.transform(items, new Function() { @Override diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java b/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java index 4db952f76c..4775c2bdb2 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/CreateVersionPage.java @@ -34,6 +34,10 @@ public class CreateVersionPage extends BasePage { + public final static String VALIDATION_ERROR = + "must start and end with letter or number, and contain only " + + "letters, numbers, periods, underscores and hyphens."; + @FindBy(id = "create-version-form:project-type") private WebElement projectTypeSelection; @@ -77,7 +81,7 @@ public CreateVersionPage selectProjectType(String projectType) { projectTypeSelection.findElements(By.tagName("li")); for (WebElement projectTypeLi : projectTypes) { if (projectTypeLi.findElement(By.xpath(".//div/label")).getText() - .equals(projectType)) { + .startsWith(projectType)) { projectTypeLi.findElement(By.xpath(".//div")).click(); break; } diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java b/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java index 526be61c43..cb06505a89 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/VersionDocumentsPage.java @@ -25,6 +25,7 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import java.util.ArrayList; import java.util.List; /** @@ -58,6 +59,15 @@ public boolean sourceDocumentsContains(String document) { return false; } + public List getSourceDocumentNames() { + List filenames = new ArrayList(); + for (WebElement element : getDocumentsTabDocumentList()) { + filenames.add(element.findElement(By.className("list__title")) + .getText()); + } + return filenames; + } + private List getDocumentsTabDocumentList() { waitForTenSec().until(new Predicate() { @Override diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionDocumentsTab.java b/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionDocumentsTab.java index 53e36a6b2d..e83a597814 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionDocumentsTab.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionDocumentsTab.java @@ -1,12 +1,14 @@ package org.zanata.page.projectversion.versionsettings; +import java.util.ArrayList; import java.util.List; +import com.google.common.base.Predicate; import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.zanata.page.projectversion.VersionBasePage; -import org.zanata.page.projectversion.VersionLanguagesPage; /** * @author Damian Jansen () { + @Override + public boolean apply( WebDriver input) { + return !getDriver().findElement(By.id("file-upload-component")) + .isDisplayed(); + } + }); return new VersionDocumentsTab(getDriver()); } public VersionDocumentsTab enterFilePath(String filePath) { - getDriver().findElement(By.id("uploadDocForm:generalDocFileUpload")) + // Make the hidden input element slightly not hidden + ((JavascriptExecutor)getDriver()) + .executeScript("arguments[0].style.visibility = 'visible'; " + + "arguments[0].style.height = '1px'; " + + "arguments[0].style.width = '1px'; " + + "arguments[0].style.opacity = 1", + getDriver().findElement( + By.id("file-upload-component-file-input"))); + + getDriver().findElement( + By.id("file-upload-component-file-input")) .sendKeys(filePath); return new VersionDocumentsTab(getDriver()); } - public VersionLanguagesPage submitUpload() { + public VersionDocumentsTab submitUpload() { + waitForTenSec().until(new Predicate() { + @Override + public boolean apply(WebDriver input) { + return getDriver().findElement( + By.id("file-upload-component-start-upload")) + .isEnabled(); + } + }); getDriver().findElement( - By.id("uploadDocForm:generalDocSubmitUploadButton")).click(); - return new VersionLanguagesPage(getDriver()); + By.id("file-upload-component-start-upload")).click(); + return new VersionDocumentsTab(getDriver()); } - public boolean sourceDocumentsContains(String document) { + public VersionDocumentsTab clickUploadDone() { + waitForTenSec().until(new Predicate() { + @Override + public boolean apply(WebDriver input) { + return getDriver() + .findElement(By.id("file-upload-component-done-upload")) + .isEnabled(); + } + }); + getDriver().findElement(By.id("file-upload-component-done-upload")) + .click(); + return new VersionDocumentsTab(getDriver()); + } + public boolean sourceDocumentsContains(String document) { List documentLabelList = getDriver() .findElement(By.id("settings-document_form")) @@ -67,4 +108,43 @@ public boolean sourceDocumentsContains(String document) { } return false; } + + public List getUploadList() { + List filenames = new ArrayList(); + for (WebElement element : getUploadListElements()) { + filenames.add(element.findElement(By.className("list__title")) + .getText()); + } + return filenames; + } + + public VersionDocumentsTab clickRemoveOn(String filename) { + for (WebElement element : getUploadListElements()) { + if (element.findElement(By.className("list__title")) + .getText().equals(filename)) { + element.findElement(By.className("list__item__actions")) + .findElement(By.className("cancel")) + .click(); + } + } + return new VersionDocumentsTab(getDriver()); + } + + private List getUploadListElements() { + return getDriver().findElement(By.className("js-files-panel")) + .findElement(By.tagName("ul")) + .findElements(By.tagName("li")); + } + + public String getUploadError() { + waitForTenSec().until(new Predicate() { + @Override + public boolean apply(WebDriver input) { + return getDriver().findElement(By.id("file-upload-component")) + .findElement(By.className("txt--danger")).isDisplayed(); + } + }); + return getDriver().findElement(By.id("file-upload-component")) + .findElement(By.className("txt--danger")).getText(); + } } diff --git a/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionLanguagesTab.java b/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionLanguagesTab.java index 5d45f8c958..4496e0877c 100644 --- a/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionLanguagesTab.java +++ b/functional-test/src/main/java/org/zanata/page/projectversion/versionsettings/VersionLanguagesTab.java @@ -144,29 +144,25 @@ public boolean apply(WebDriver driver) { } public VersionLanguagesTab addLocale(final String localeId) { - waitForTenSec().until(new Function>() { + String message = "can not find locale - " + localeId; + waitForTenSec().withMessage(message).until(new Predicate() { @Override - public List apply(WebDriver driver) { - return WebElementUtil.getSearchAutocompleteResults(driver, - "settings-languages-form", "languageAutocomplete"); + public boolean apply(WebDriver driver) { + List searchResults = + WebElementUtil.getSearchAutocompleteResults(driver, + "settings-languages-form", + "languageAutocomplete"); + + for (WebElement searchResult : searchResults) { + if (searchResult.getText().contains(localeId)) { + searchResult.click(); + return true; + } + } + return false; } }); - List searchResults = - WebElementUtil.getSearchAutocompleteResults(getDriver(), - "settings-languages-form", "languageAutocomplete"); - - boolean clickedLocale = false; - for (WebElement searchResult : searchResults) { - if (searchResult.getText().contains(localeId)) { - searchResult.click(); - clickedLocale = true; - break; - } - } - Preconditions.checkState(clickedLocale, "can not find locale - %s", - localeId); - refreshPageUntil(this, new Predicate() { @Override public boolean apply(WebDriver driver) { diff --git a/functional-test/src/main/java/org/zanata/page/utility/HomePage.java b/functional-test/src/main/java/org/zanata/page/utility/HomePage.java index 897ad94b94..21a18c327b 100644 --- a/functional-test/src/main/java/org/zanata/page/utility/HomePage.java +++ b/functional-test/src/main/java/org/zanata/page/utility/HomePage.java @@ -30,6 +30,10 @@ public class HomePage extends BasePage { + public static final String SIGNUP_SUCCESS_MESSAGE = + "You will soon receive an email " + + "with a link to activate your account."; + @FindBy(id = "main_body_content") private WebElement mainBodyContent; diff --git a/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java b/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java index 5d9ea006fc..08b19f712a 100644 --- a/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java +++ b/functional-test/src/main/java/org/zanata/page/webtrans/EditorPage.java @@ -20,13 +20,16 @@ */ package org.zanata.page.webtrans; -import java.awt.*; +import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.util.Collections; import java.util.List; -import org.openqa.selenium.*; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.FindBy; import org.zanata.page.BasePage; @@ -208,6 +211,20 @@ public String getBasicTranslationTargetAtRowIndex(final int rowIndex) { return getContentAtRowIndex(rowIndex, TARGET_ID_FMT, Plurals.TargetSingular); } + public String getBasicTranslationTargetAtRowIndex(int rowIndex, Plurals plurals) { + return getContentAtRowIndex(rowIndex, TARGET_ID_FMT, plurals); + } + + public boolean expectBasicTranslationAtRowIndex(final int rowIndex, + final String expected) { + return waitForTenSec().until(new Function() { + @Override + public Boolean apply(WebDriver input) { + return getBasicTranslationTargetAtRowIndex(rowIndex).equals(expected); + } + }); + } + private String getContentAtRowIndex(final long rowIndex, final String idFormat, final Plurals plural) { diff --git a/functional-test/src/main/java/org/zanata/rest/SampleDataResource.java b/functional-test/src/main/java/org/zanata/rest/SampleDataResource.java index 3e1c02a773..3106609441 100644 --- a/functional-test/src/main/java/org/zanata/rest/SampleDataResource.java +++ b/functional-test/src/main/java/org/zanata/rest/SampleDataResource.java @@ -27,7 +27,7 @@ public interface SampleDataResource { @PUT @Path("/accounts/u/{username}/languages") Response userJoinsLanguageTeams(@PathParam("username") String username, - @QueryParam("locales") Set locales); + @QueryParam("locales") String localesCSV); @PUT @Path("/users") diff --git a/functional-test/src/main/java/org/zanata/rest/SampleDataResourceImpl.java b/functional-test/src/main/java/org/zanata/rest/SampleDataResourceImpl.java index 70bfa34a2f..038b0c9d9f 100644 --- a/functional-test/src/main/java/org/zanata/rest/SampleDataResourceImpl.java +++ b/functional-test/src/main/java/org/zanata/rest/SampleDataResourceImpl.java @@ -1,13 +1,16 @@ package org.zanata.rest; import java.util.List; -import java.util.Set; import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; import javax.persistence.EntityManager; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; + +import lombok.extern.slf4j.Slf4j; + import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Transactional; @@ -16,9 +19,12 @@ import org.zanata.model.HLocale; import org.zanata.model.HPerson; import org.zanata.util.SampleProjectProfile; + +import com.google.common.base.Function; +import com.google.common.base.Splitter; import com.google.common.base.Strings; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.Uninterruptibles; -import lombok.extern.slf4j.Slf4j; /** * @author Patrick Huang locales) { - + @QueryParam("locales") String localesCSV) { + List localesIds = Lists.newArrayList( + Splitter.on(",").omitEmptyStrings().trimResults().split( + localesCSV)); + List locales = + Lists.transform(localesIds, new Function() { + @Override + public LocaleId apply(String input) { + return new LocaleId(input); + } + }); final HPerson hPerson = entityManager .createQuery("from HPerson p where p.account.username = :username", HPerson.class).setParameter("username", username).getSingleResult(); diff --git a/functional-test/src/main/java/org/zanata/util/SampleProjectProfile.java b/functional-test/src/main/java/org/zanata/util/SampleProjectProfile.java index bba245a755..1f5972fc72 100644 --- a/functional-test/src/main/java/org/zanata/util/SampleProjectProfile.java +++ b/functional-test/src/main/java/org/zanata/util/SampleProjectProfile.java @@ -6,7 +6,8 @@ import org.hibernate.Session; import org.hibernate.search.FullTextSession; -import org.hibernate.search.Search; +import org.hibernate.search.jpa.FullTextEntityManager; +import org.hibernate.search.jpa.Search; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; @@ -18,6 +19,7 @@ import org.zanata.model.Activity; import org.zanata.model.HAccount; import org.zanata.model.HAccountActivationKey; +import org.zanata.model.HAccountResetPasswordKey; import org.zanata.model.HAccountRole; import org.zanata.model.HApplicationConfiguration; import org.zanata.model.HDocument; @@ -31,6 +33,7 @@ import org.zanata.model.HPersonEmailValidationKey; import org.zanata.model.HProject; import org.zanata.model.HProjectIteration; +import org.zanata.model.HRoleAssignmentRule; import org.zanata.model.HTermComment; import org.zanata.model.HTextFlow; import org.zanata.model.HTextFlowTarget; @@ -92,7 +95,11 @@ public void deleteExceptEssentialData() { HProjectIteration.class, HProject.class, // account HAccountActivationKey.class, HPersonEmailValidationKey.class, - HCredentials.class, HPerson.class, HAccount.class)); + HAccountResetPasswordKey.class, HCredentials.class, + HPerson.class, HAccount.class, + // account role + HRoleAssignmentRule.class + )); enUSLocale = forLocale(false, LocaleId.EN_US).makeAndPersist(entityManager, HLocale.class); @@ -125,17 +132,20 @@ public void deleteExceptEssentialData() { } private void purgeLuceneIndexes() { - FullTextSession fullTextSession = - Search.getFullTextSession((Session) entityManagerFactory - .createEntityManager().getDelegate()); - - fullTextSession.purgeAll(HAccount.class); - fullTextSession.purgeAll(HGlossaryEntry.class); - fullTextSession.purgeAll(HGlossaryTerm.class); - fullTextSession.purgeAll(HProject.class); - fullTextSession.purgeAll(HProjectIteration.class); - fullTextSession.purgeAll(TransMemoryUnit.class); - fullTextSession.purgeAll(HTextFlowTarget.class); + FullTextEntityManager em = + Search.getFullTextEntityManager( + entityManagerFactory.createEntityManager()); + try { + em.purgeAll(HAccount.class); + em.purgeAll(HGlossaryEntry.class); + em.purgeAll(HGlossaryTerm.class); + em.purgeAll(HProject.class); + em.purgeAll(HProjectIteration.class); + em.purgeAll(TransMemoryUnit.class); + em.purgeAll(HTextFlowTarget.class); + } finally { + em.close(); + } } public void makeSampleLanguages() { diff --git a/functional-test/src/main/java/org/zanata/util/TestEventForScreenshotListener.java b/functional-test/src/main/java/org/zanata/util/TestEventForScreenshotListener.java index ec002f6778..507951f09c 100644 --- a/functional-test/src/main/java/org/zanata/util/TestEventForScreenshotListener.java +++ b/functional-test/src/main/java/org/zanata/util/TestEventForScreenshotListener.java @@ -100,7 +100,11 @@ public void afterClickOn(WebElement element, WebDriver driver) { @Override public void onException(Throwable throwable, WebDriver driver) { - createScreenshot("_exc"); + try { + createScreenshot("_exc"); + } catch (Throwable all) { + log.error("error creating screenshot on exception"); + } } } diff --git a/functional-test/src/main/java/org/zanata/util/TestFileGenerator.java b/functional-test/src/main/java/org/zanata/util/TestFileGenerator.java index a7632f9b18..bb965d02ab 100644 --- a/functional-test/src/main/java/org/zanata/util/TestFileGenerator.java +++ b/functional-test/src/main/java/org/zanata/util/TestFileGenerator.java @@ -53,10 +53,12 @@ public class TestFileGenerator { // Length is maximum filename length - 4 (.xxx) - 19 (for tmp file // randomness) - private static String longFileName = - "lRRDXddgEnKzT2Wpu3VfT3Zs4pYuPXaqorA1CAtGcaZq6xydHdOghbsy" - + "Pu5GnbbmknPNRZ0vc7IEaiPm59CBQ9NkIH1if9Y4uHHYgjWJT8Yhs5qibcEZDNAZwLmDNHaRJhQr2Y1z3VslMFGGS" - + "P25eqzU1lDjejCsd26wRhT1UOkbhRRlm0ybGk8lTQgHEqT9sno1Veuw8A0StLGDfHAmCDFcUzAz9HMeuMUn9nFW"; + private static String longFileName = "lRRDXddgEnKzT2Wpu3VfT3Zs4pYuPXaqorA" + + "1CAtGcaZq6xydHdOghbsyPu5GnbbmknPNRZ0vc7IEaiPm59CBQ9NkIH1if9Y4uHH" + + "YgjWJT8Yhs5qibcEZDNAZwLmDNHaRJhQr2Y1z3VslMFGGSP25eqzU1lDjejCsd26" + + "wRhT1UOkbhRRlm0ybGk8lTQgHEqT9sno1Veuw8A0StLGDfHAmCDFcUzAz9HMeuMU" + + "n9nFW"; + public TestFileGenerator() { } diff --git a/functional-test/src/test/java/org/zanata/feature/Feature.java b/functional-test/src/test/java/org/zanata/feature/Feature.java new file mode 100644 index 0000000000..942dbd6753 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/Feature.java @@ -0,0 +1,21 @@ +package org.zanata.feature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +/** + * @author Patrick Huang + * pahuang@redhat.com + */ +public @interface Feature { + int NO_BUG = 0; + + int bugzilla() default NO_BUG; + String summary() default "no description"; + int[] tcmsTestPlanIds() default {}; + int[] tcmsTestCaseIds() default {}; +} diff --git a/functional-test/src/test/java/org/zanata/feature/account/ChangePasswordTest.java b/functional-test/src/test/java/org/zanata/feature/account/ChangePasswordTest.java index 3a192722e9..0b43dd7699 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/ChangePasswordTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/ChangePasswordTest.java @@ -20,24 +20,21 @@ */ package org.zanata.feature.account; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.dashboard.DashboardBasePage; import org.zanata.page.dashboard.dashboardsettings.DashboardAccountTab; -import org.zanata.page.utility.HomePage; import org.zanata.util.AddUsersRule; import org.zanata.workflow.BasicWorkFlow; import org.zanata.workflow.LoginWorkFlow; -import java.util.List; - -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Damian Jansen fieldErrors = - new LoginWorkFlow().signIn("translator", "translator") - .goToSettingsTab() - .gotoSettingsAccountTab() - .typeOldPassword("nottherightpassword") - .typeNewPassword("somenewpassword") - .clickUpdatePasswordButton() - .getFieldErrors(); - - assertThat("Incorrect password message displayed", - fieldErrors, - Matchers.contains(incorrectPassword)); + @Feature(summary = "The user must enter their current password correctly " + + "to change it", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86823) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changePasswordCurrentPasswordFailure() throws Exception { + DashboardAccountTab dashboardAccountTab = new LoginWorkFlow() + .signIn("translator", "translator") + .goToSettingsTab() + .gotoSettingsAccountTab() + .typeOldPassword("nottherightpassword") + .typeNewPassword("somenewpassword") + .clickUpdatePasswordButton(); + + assertThat(dashboardAccountTab.getFieldErrors()) + .contains(DashboardAccountTab.INCORRECT_OLD_PASSWORD_ERROR) + .as("The old password incorrect error is shown"); } - @Test - public void changePasswordRequiredFieldsAreNotEmpty() { - String mayNotBeEmpty = "may not be empty"; - List fieldErrors = - new LoginWorkFlow().signIn("translator", "translator") - .goToSettingsTab() - .gotoSettingsAccountTab() - .clickUpdatePasswordButton() - .getFieldErrors(); - - assertThat("Incorrect password message displayed", - fieldErrors, - Matchers.contains(mayNotBeEmpty, mayNotBeEmpty)); + @Feature(summary = "The user must enter a non-empty new password " + + "to change it", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86823) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changePasswordRequiredFieldsAreNotEmpty() throws Exception { + DashboardAccountTab dashboardAccountTab = new LoginWorkFlow() + .signIn("translator", "translator") + .goToSettingsTab() + .gotoSettingsAccountTab() + .clickUpdatePasswordButton(); + + assertThat(dashboardAccountTab.getFieldErrors()) + .contains(DashboardAccountTab.FIELD_EMPTY_ERROR) + .as("Empty password message displayed"); } - @Test - public void changePasswordAreOfRequiredLength() { - String passwordSizeError = "size must be between 6 and 20"; + @Feature(summary = "The user must enter a new password of between 6 and " + + "20 characters in length to change it", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86823) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changePasswordAreOfRequiredLength() throws Exception { String tooShort = "test5"; String tooLong = "t12345678901234567890"; - DashboardAccountTab dashboardAccountTab = - new LoginWorkFlow().signIn("translator", "translator") - .goToSettingsTab() - .gotoSettingsAccountTab() - .typeOldPassword("translator"); - - List fieldErrors = - dashboardAccountTab - .typeNewPassword(tooShort) - .clickUpdatePasswordButton() - .waitForFieldErrors(); - assertThat("Incorrect password message displayed", - fieldErrors, - Matchers.hasItem(passwordSizeError)); - - fieldErrors = - dashboardAccountTab - .typeNewPassword(tooLong) - .clickUpdatePasswordButton() - .waitForFieldErrors(); - assertThat("Incorrect password message displayed", - fieldErrors, - Matchers.hasItem(passwordSizeError)); + DashboardAccountTab dashboardAccountTab = new LoginWorkFlow() + .signIn("translator", "translator") + .goToSettingsTab() + .gotoSettingsAccountTab() + .typeOldPassword("translator") + .typeNewPassword(tooShort) + .clickUpdatePasswordButton(); + + assertThat(dashboardAccountTab.getFieldErrors()) + .contains(DashboardAccountTab.PASSWORD_LENGTH_ERROR) + .as("Incorrect password length message displayed"); + + dashboardAccountTab = dashboardAccountTab + .typeNewPassword(tooLong) + .clickUpdatePasswordButton(); + + assertThat(dashboardAccountTab.getFieldErrors()) + .contains(DashboardAccountTab.PASSWORD_LENGTH_ERROR) + .as("Incorrect password length message displayed"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/account/InactiveUserLoginTest.java b/functional-test/src/test/java/org/zanata/feature/account/InactiveUserLoginTest.java index 827a014aa6..6cd6eb0e7d 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/InactiveUserLoginTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/InactiveUserLoginTest.java @@ -20,18 +20,18 @@ */ package org.zanata.feature.account; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.account.SignInPage; import org.zanata.util.AddUsersRule; import org.zanata.workflow.LoginWorkFlow; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Carlos Munoz camunoz@redhat.com @@ -42,15 +42,20 @@ public class InactiveUserLoginTest extends ZanataTestCase { @Rule public AddUsersRule addUsersRule = new AddUsersRule(); - @Test - public void loginWithInactiveUser() { + @Feature(summary = "The user needs to verify their account before they may " + + "log in", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 181714) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void loginWithInactiveUser() throws Exception { new LoginWorkFlow().signIn("admin", "admin").goToAdministration() .goToManageUserPage().editUserAccount("translator") .clickEnabled().saveUser().logout(); - SignInPage signInPage = - new LoginWorkFlow().signInFailure("translator", "translator"); - assertThat(signInPage.getNotificationMessage(), is("Login failed")); + SignInPage signInPage = new LoginWorkFlow() + .signInFailure("translator", "translator"); + assertThat(signInPage.getNotificationMessage()) + .isEqualTo(SignInPage.LOGIN_FAILED_ERROR) + .as("The inactive user cannot log in"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/account/InvalidEmailAddressTest.java b/functional-test/src/test/java/org/zanata/feature/account/InvalidEmailAddressTest.java index ea475ee050..8d0d191974 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/InvalidEmailAddressTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/InvalidEmailAddressTest.java @@ -22,15 +22,21 @@ import lombok.extern.slf4j.Slf4j; -import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; import org.junit.experimental.categories.Category; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; +import org.junit.rules.Timeout; import org.junit.runner.RunWith; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.account.RegisterPage; +import org.zanata.page.utility.HomePage; +import org.zanata.util.EnsureLogoutRule; import org.zanata.util.rfc2822.InvalidEmailAddressRFC2822; import org.zanata.workflow.BasicWorkFlow; @@ -45,6 +51,10 @@ @RunWith(Theories.class) @Category(DetailedTest.class) public class InvalidEmailAddressTest extends ZanataTestCase { + @ClassRule + public static EnsureLogoutRule logoutRule = new EnsureLogoutRule(); + @Rule + public Timeout timeout = new Timeout(ZanataTestCase.MAX_LONG_TEST_DURATION); @DataPoint public static InvalidEmailAddressRFC2822 TEST_PLAIN_ADDRESS = PLAIN_ADDRESS; @@ -167,23 +177,21 @@ public class InvalidEmailAddressTest extends ZanataTestCase { // BUG982048 @DataPoint public static InvalidEmailAddressRFC2822 // TEST_MULTIPLE_DASHES_DOMAIN = MULTIPLE_DASHES_DOMAIN; - @Before - public void setUp() { - new BasicWorkFlow().goToHome().deleteCookiesAndRefresh(); - } - + @Feature(summary = "The user must enter a valid email address to " + + "register with Zanata", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) @Theory - public void invalidEmailRejection(InvalidEmailAddressRFC2822 emailAddress) { + public void invalidEmailRejection(InvalidEmailAddressRFC2822 emailAddress) + throws Exception { log.info(testName.getMethodName() + " : " + emailAddress); - String errorMsg = "not a well-formed email address"; - RegisterPage registerPage = new BasicWorkFlow() .goToHome() .goToRegistration() - .enterEmail(emailAddress.toString()); - registerPage.defocus(); + .enterEmail(emailAddress.toString()) + .registerFailure(); - assertThat(errorMsg).isIn(registerPage.waitForFieldErrors()) + assertThat(registerPage.waitForFieldErrors()) + .contains(RegisterPage.MALFORMED_EMAIL_ERROR) .as("The email formation error is displayed"); } diff --git a/functional-test/src/test/java/org/zanata/feature/account/ProfileTest.java b/functional-test/src/test/java/org/zanata/feature/account/ProfileTest.java index 2f68a7d4aa..6fc0b01643 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/ProfileTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/ProfileTest.java @@ -23,8 +23,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.page.account.RegisterPage; import org.zanata.page.dashboard.dashboardsettings.DashboardAccountTab; import org.zanata.page.dashboard.dashboardsettings.DashboardClientTab; import org.zanata.page.dashboard.dashboardsettings.DashboardProfileTab; @@ -49,8 +51,10 @@ public class ProfileTest extends ZanataTestCase { private static final String serverUrl = PropertiesHolder .getProperty(Constants.zanataInstance.value()); - @Test - public void verifyProfileData() { + @Feature(summary = "The user can view their account details", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86819) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void verifyProfileData() throws Exception { DashboardClientTab dashboardClientTab = new LoginWorkFlow() .signIn("admin", "admin") .goToSettingsTab() @@ -72,15 +76,18 @@ public void verifyProfileData() { .as("The configuration api key is correct"); } - @Test - public void changeUsersApiKey() { + @Feature(summary = "The user can change their API key", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeUsersApiKey() throws Exception { DashboardClientTab dashboardClientTab = new LoginWorkFlow() .signIn("translator", "translator") .goToSettingsTab() .goToSettingsClientTab(); String currentApiKey = dashboardClientTab.getApiKey(); dashboardClientTab = dashboardClientTab.pressApiKeyGenerateButton(); - dashboardClientTab.waitForLoaderFinished(); + + dashboardClientTab.waitForApiKeyChanged(currentApiKey); assertThat(dashboardClientTab.getApiKey()).isNotEqualTo(currentApiKey) .as("The user's api key is different"); @@ -94,22 +101,27 @@ public void changeUsersApiKey() { .as("The configuration api key matches the label"); } - @Test - public void changeUsersName() { + @Feature(summary = "The user can change their display name", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86822) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeUsersName() throws Exception { DashboardProfileTab dashboardProfileTab = new LoginWorkFlow() .signIn("translator", "translator") .goToSettingsTab() .goToSettingsProfileTab() .enterName("Tranny") .clickUpdateProfileButton(); - dashboardProfileTab.waitForLoaderFinished(); + + dashboardProfileTab.waitForUsernameChanged("translator"); assertThat(dashboardProfileTab.getUserFullName()).isEqualTo("Tranny") .as("The user's name has been changed"); } - @Test - public void emailValidationIsUsedOnProfileEdit() { + @Feature(summary = "The user's email address change is validated", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86822) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void emailValidationIsUsedOnProfileEdit() throws Exception { DashboardAccountTab dashboardAccountTab = new LoginWorkFlow() .signIn("translator", "translator") .goToSettingsTab() @@ -118,7 +130,7 @@ public void emailValidationIsUsedOnProfileEdit() { .clickUpdateEmailButton(); assertThat(dashboardAccountTab.waitForFieldErrors()) - .contains("This email address is already taken") + .contains(DashboardAccountTab.EMAIL_TAKEN_ERROR) .as("The email is rejected, being already taken"); dashboardAccountTab = dashboardAccountTab @@ -129,7 +141,7 @@ public void emailValidationIsUsedOnProfileEdit() { .clickUpdateEmailButton(); assertThat(dashboardAccountTab.waitForFieldErrors()) - .contains("not a well-formed email address") + .contains(RegisterPage.MALFORMED_EMAIL_ERROR) .as("The email is rejected, being of invalid format"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java b/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java index 7318f49a69..964a28f412 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/RegisterTest.java @@ -20,28 +20,29 @@ */ package org.zanata.feature.account; -import static org.hamcrest.MatcherAssert.assertThat; - import java.util.HashMap; import java.util.List; import java.util.Map; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.ClassRule; import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.account.RegisterPage; +import org.zanata.page.account.SignInPage; import org.zanata.page.utility.HomePage; import org.zanata.util.AddUsersRule; import org.zanata.util.HasEmailRule; import org.zanata.util.rfc2822.InvalidEmailAddressRFC2822; import org.zanata.workflow.BasicWorkFlow; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Damian Jansen djansen@redhat.com @@ -72,63 +73,73 @@ public void before() { homePage.deleteCookiesAndRefresh(); } - @Test + @Feature(summary = "The user can register an account with Zanata", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86816) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) @Category(BasicAcceptanceTest.class) - public void registerSuccessful() { - String successMessage = "You will soon receive an email with a link "+ - "to activate your account."; + public void registerSuccessful() throws Exception { RegisterPage registerPage = homePage .goToRegistration() .setFields(fields); - assertThat("No errors are shown", registerPage.getFieldErrors().size(), - Matchers.equalTo(0)); + assertThat(registerPage.getFieldErrors().size()).isEqualTo(0) + .as("No errors are shown"); homePage = registerPage.register(); - assertThat("Signup is successful", homePage.getNotificationMessage(), - Matchers.equalTo(successMessage)); + assertThat(homePage.getNotificationMessage()) + .isEqualTo(HomePage.SIGNUP_SUCCESS_MESSAGE) + .as("Sign up is successful"); } - @Test - public void usernameLengthValidation() { + @Feature(summary = "The user must enter a username of between 3 and " + + "20 (inclusive) characters to register", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void usernameLengthValidation() throws Exception { fields.put("email", "length.test@test.com"); RegisterPage registerPage = homePage.goToRegistration(); fields.put("username", "bo"); registerPage = registerPage.setFields(fields); - registerPage.defocus(); - assertThat("Size errors are shown for string too short", - containsUsernameError(registerPage.getFieldErrors())); + + assertThat(containsUsernameError(registerPage.getFieldErrors())) + .isTrue() + .as("Size errors are shown for string too short"); fields.put("username", "testusername"); registerPage = registerPage.setFields(fields); - registerPage.defocus(); - assertThat("Size errors are not shown", - !containsUsernameError(registerPage.getFieldErrors())); + + assertThat(containsUsernameError(registerPage.getFieldErrors())) + .isFalse() + .as("Size errors are not shown"); fields.put("username", "12345678901234567890a"); registerPage = registerPage.setFields(fields); - registerPage.defocus(); - assertThat("Size errors are shown for string too long", - containsUsernameError(registerPage.getFieldErrors())); + + assertThat(containsUsernameError(registerPage.getFieldErrors())) + .isTrue() + .as("Size errors are shown for string too long"); } - @Test - public void usernamePreExisting() { - String errorMsg = "This username is not available"; + @Feature(summary = "The user must enter a unique username to register", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void usernamePreExisting() throws Exception { RegisterPage registerPage = homePage .goToRegistration() .enterUserName("admin"); registerPage.defocus(); - assertThat("Username not available message is shown", - registerPage.waitForFieldErrors(), Matchers.hasItem(errorMsg)); + assertThat(registerPage.waitForFieldErrors()) + .contains(RegisterPage.USERNAME_UNAVAILABLE_ERROR) + .as("Username not available message is shown"); } - @Test - public void emailValidation() { - String errorMsg = "not a well-formed email address"; + @Feature(summary = "The user must enter a valid email address to register", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void emailValidation() throws Exception { fields.put("email", InvalidEmailAddressRFC2822.PLAIN_ADDRESS.toString()); fields.put("username", "emailvalidation"); @@ -137,33 +148,86 @@ public void emailValidation() { .setFields(fields); registerPage.defocus(); - assertThat("Email validation errors are shown", - registerPage.getFieldErrors(), Matchers.hasItem(errorMsg)); + assertThat(registerPage.getFieldErrors()) + .contains(RegisterPage.MALFORMED_EMAIL_ERROR) + .as("Email validation errors are shown"); } - @Test + @Feature(summary = "The user must enter all necessary fields to register", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) @Ignore("RHBZ-1024150") - public void requiredFields() { - String errorMsg = "value is required"; + public void requiredFields() throws Exception { fields.put("name", ""); fields.put("username", ""); fields.put("email", ""); fields.put("password", ""); - RegisterPage registerPage = homePage.goToRegistration().setFields(fields); registerPage.defocus(); - assertThat("Value is required shows for all fields", - registerPage.waitForFieldErrors(), - Matchers.contains(errorMsg, - registerPage.USERNAMEVALIDATIONERROR, - errorMsg, errorMsg)); + assertThat(registerPage.waitForFieldErrors()).containsExactly( + RegisterPage.REQUIRED_FIELD_ERROR, + RegisterPage.USERNAME_VALIDATION_ERROR, + RegisterPage.REQUIRED_FIELD_ERROR, + RegisterPage.REQUIRED_FIELD_ERROR) + .as("Value is required shows for all fields"); } - /* - * Bugs - */ + @Feature(summary = "The user can access the login page from the register " + + "page, and vice versa", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test + public void signUpToLoginAndBack() { + RegisterPage registerPage = new BasicWorkFlow() + .goToHome() + .clickSignInLink() + .goToRegister(); + + assertThat(registerPage.getPageTitle()) + .isEqualTo("Sign up with Zanata") + .as("The user is sent to the register page"); + + SignInPage signInPage = registerPage.goToSignIn(); + + assertThat(signInPage.getPageTitle()) + .isEqualTo("Log in with your username") + .as("The user is sent to the log in page"); + } + + @Feature(summary = "The user can toggle the entered password visible and " + + "masked", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test + public void togglePasswordVisible() { + RegisterPage registerPage = new BasicWorkFlow() + .goToHome() + .goToRegistration() + .enterPassword("mypassword"); + + assertThat(registerPage.getPasswordFieldType()) + .isEqualTo("password") + .as("The password field starts as masked"); + + registerPage = registerPage.clickPasswordShowToggle(); + + assertThat(registerPage.getPasswordFieldType()) + .isEqualTo("text") + .as("The password field is now not masked"); + + registerPage = registerPage.clickPasswordShowToggle(); + + assertThat(registerPage.getPasswordFieldType()) + .isEqualTo("password") + .as("The password field is again masked"); + assertThat(registerPage.getPassword()) + .isEqualTo("mypassword") + .as("The password field did not lose the entered text"); + } + + @Feature(summary = "The user must enter at least one alphanumeric " + + "character in their username", + bugzilla = 981498) @Test(expected = AssertionError.class) public void bug981498_underscoreRules() { fields.put("email", "bug981498test@example.com"); @@ -171,9 +235,10 @@ public void bug981498_underscoreRules() { RegisterPage registerPage = homePage.goToRegistration().setFields(fields); registerPage.defocus(); - assertThat("A username of all underscores is not valid", - registerPage.getFieldErrors(), - Matchers.hasItem(registerPage.USERNAMEVALIDATIONERROR)); + + assertThat(registerPage.getFieldErrors()) + .contains(RegisterPage.USERNAME_VALIDATION_ERROR) + .as("A username of all underscores is not valid"); } /* @@ -181,8 +246,7 @@ public void bug981498_underscoreRules() { * the given input. */ private boolean containsUsernameError(List errors) { - return errors.contains("Between 3 and 20 lowercase "+ - "letters, numbers and underscores only") || - errors.contains("size must be between 3 and 20"); + return errors.contains(RegisterPage.USERNAME_VALIDATION_ERROR) || + errors.contains(RegisterPage.USERNAME_LENGTH_ERROR); } } diff --git a/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java b/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java index 9111790bb6..4f121eb440 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/UsernameValidationTest.java @@ -22,11 +22,14 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Before; +import org.junit.Rule; import org.junit.experimental.categories.Category; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; +import org.junit.rules.Timeout; import org.junit.runner.RunWith; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.account.RegisterPage; @@ -43,6 +46,9 @@ @Category(DetailedTest.class) public class UsernameValidationTest extends ZanataTestCase { + @Rule + public Timeout timeout = new Timeout(ZanataTestCase.MAX_LONG_TEST_DURATION); + @DataPoint public static String INVALID_PIPE = "user|name"; @DataPoint @@ -101,8 +107,11 @@ public void setUp() { new BasicWorkFlow().goToHome().deleteCookiesAndRefresh(); } + @Feature(summary = "The user must enter acceptable username characters" + + "to register", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) @Theory - public void usernameCharacterValidation(String username) { + public void usernameCharacterValidation(String username) throws Exception { log.info(testName.getMethodName() + " : " + username); RegisterPage registerPage = new BasicWorkFlow() .goToHome() @@ -111,7 +120,7 @@ public void usernameCharacterValidation(String username) { registerPage.defocus(); assertThat(registerPage.waitForFieldErrors()) - .contains(registerPage.USERNAMEVALIDATIONERROR) + .contains(RegisterPage.USERNAME_VALIDATION_ERROR) .as("Username validation errors are shown"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/account/ValidEmailAddressTest.java b/functional-test/src/test/java/org/zanata/feature/account/ValidEmailAddressTest.java index d9c3d3581d..6e0626abe5 100644 --- a/functional-test/src/test/java/org/zanata/feature/account/ValidEmailAddressTest.java +++ b/functional-test/src/test/java/org/zanata/feature/account/ValidEmailAddressTest.java @@ -22,11 +22,14 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Before; +import org.junit.Rule; import org.junit.experimental.categories.Category; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; +import org.junit.rules.Timeout; import org.junit.runner.RunWith; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.account.RegisterPage; @@ -45,6 +48,9 @@ @Category(DetailedTest.class) public class ValidEmailAddressTest extends ZanataTestCase { + @Rule + public Timeout timeout = new Timeout(ZanataTestCase.MAX_LONG_TEST_DURATION); + @DataPoint public static ValidEmailAddressRFC2822 TEST_BASIC_EMAIL = BASIC_EMAIL; @DataPoint @@ -97,18 +103,21 @@ public void setUp() { new BasicWorkFlow().goToHome().deleteCookiesAndRefresh(); } + @Feature(summary = "The system will allow all acceptable forms of " + + "email address for registration", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) @Theory - public void validEmailAcceptance(ValidEmailAddressRFC2822 emailAddress) { + public void validEmailAcceptance(ValidEmailAddressRFC2822 emailAddress) + throws Exception { log.info(testName.getMethodName() + " : " + emailAddress); - String errorMsg = "not a well-formed email address"; RegisterPage registerPage = new BasicWorkFlow() .goToHome() .goToRegistration() .enterEmail(emailAddress.toString()) .registerFailure(); - registerPage.defocus(); - assertThat(errorMsg).isNotIn(registerPage.getFieldErrors()) + assertThat(RegisterPage.MALFORMED_EMAIL_ERROR) + .isNotIn(registerPage.getFieldErrors()) .as("Email validation errors are not shown"); } diff --git a/functional-test/src/test/java/org/zanata/feature/administration/AutoRoleAssignmentTest.java b/functional-test/src/test/java/org/zanata/feature/administration/AutoRoleAssignmentTest.java new file mode 100644 index 0000000000..55b555e782 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/administration/AutoRoleAssignmentTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.feature.administration; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; +import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.page.administration.RoleAssignmentsPage; +import org.zanata.util.AddUsersRule; +import org.zanata.workflow.LoginWorkFlow; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Damian Jansen djansen@redhat.com + */ +@Category(DetailedTest.class) +public class AutoRoleAssignmentTest extends ZanataTestCase { + + @Rule + public AddUsersRule addUsersRule = new AddUsersRule(); + + @Feature(summary = "The administrator can create a rule to assign roles " + + "at user sign in", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void createAutoRoleAssignment() throws Exception { + RoleAssignmentsPage roleAssignmentsPage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToAdministration() + .goToManageRoleAssignments() + .clickCreateNew() + .enterIdentityPattern(".+ransla.+") + .selectRole("admin") + .saveRoleAssignment() + .cancelEditRoleAssignment(); + + assertThat(roleAssignmentsPage.getRulesByPattern()) + .contains(".+ransla.+") + .as("The rule was created"); + + roleAssignmentsPage.logout(); + { + // TODO: Bug? Remove me + new LoginWorkFlow() + .signIn("translator", "translator") + .logout(); + } + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .goToAdministration() + .getTitle()).isEqualTo("Zanata: Administration") + .as("The translator user was automatically given admin rights"); + } +} diff --git a/functional-test/src/test/java/org/zanata/feature/administration/EditHomePageTest.java b/functional-test/src/test/java/org/zanata/feature/administration/EditHomePageTest.java index 46fab064fd..0e53765684 100644 --- a/functional-test/src/test/java/org/zanata/feature/administration/EditHomePageTest.java +++ b/functional-test/src/test/java/org/zanata/feature/administration/EditHomePageTest.java @@ -20,21 +20,17 @@ */ package org.zanata.feature.administration; -import org.hamcrest.Matchers; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; -import org.zanata.page.administration.EditHomeCodePage; -import org.zanata.page.administration.EditHomeContentPage; -import org.zanata.page.dashboard.DashboardBasePage; import org.zanata.page.utility.HomePage; import org.zanata.util.AddUsersRule; import org.zanata.workflow.LoginWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Damian Jansen Test") + .update(); - assertThat("Correct page", editHomeCodePage.getTitle(), - Matchers.equalTo("Zanata: Edit Page Code")); - HomePage homePage = editHomeCodePage.enterText("Test").update(); - assertThat("Message displayed", homePage.getNotificationMessage(), - Matchers.equalTo("Home content was successfully updated.")); - editHomeCodePage = homePage.goToEditPageCode(); - homePage = editHomeCodePage.cancelUpdate(); - assertThat("Homepage text has been updated", - homePage.getMainBodyContent(), Matchers.equalTo("Test")); + assertThat(homePage.getMainBodyContent()).isEqualTo("Test") + .as("Homepage text has been updated"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/administration/EditTranslationMemoryTest.java b/functional-test/src/test/java/org/zanata/feature/administration/EditTranslationMemoryTest.java index 7cbd4046f1..be1f1c18b2 100644 --- a/functional-test/src/test/java/org/zanata/feature/administration/EditTranslationMemoryTest.java +++ b/functional-test/src/test/java/org/zanata/feature/administration/EditTranslationMemoryTest.java @@ -20,15 +20,13 @@ */ package org.zanata.feature.administration; -import static org.hamcrest.MatcherAssert.assertThat; - import java.io.File; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.openqa.selenium.Alert; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.administration.TranslationMemoryEditPage; @@ -39,6 +37,8 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.TranslationMemoryWorkFlow; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Damian Jansen djansen@redhat.com @@ -53,282 +53,250 @@ public class EditTranslationMemoryTest extends ZanataTestCase { @Before public void before() { - assertThat("Admin is logged in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - Matchers.equalTo("admin")); + assertThat(new LoginWorkFlow().signIn("admin", "admin").loggedInAs()) + .isEqualTo("admin") + .as("Admin is logged in"); } - @Test - public void createNewTranslationMemory() { + @Feature(summary = "The administrator can create a new translation " + + "memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void createNewTranslationMemory() throws Exception { String newTMId = "newtmtest"; String tmDescription = "A new test TM"; TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow().createTranslationMemory( - newTMId, tmDescription); + new TranslationMemoryWorkFlow() + .createTranslationMemory(newTMId, tmDescription); - assertThat("The success message is displayed", - translationMemoryPage.getNotificationMessage(), - Matchers.equalTo("Successfully created")); + assertThat(translationMemoryPage + .expectNotification("Successfully created")) + .isTrue() + .as("The success message is displayed"); - assertThat("The new Translation Memory is listed", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.hasItem(newTMId)); + assertThat(translationMemoryPage.getListedTranslationMemorys()) + .contains(newTMId) + .as("The new Translation Memory is listed"); - assertThat("The description is displayed correctly", - translationMemoryPage.getDescription(newTMId), - Matchers.equalTo(tmDescription)); + assertThat(translationMemoryPage.getDescription(newTMId)) + .isEqualTo(tmDescription) + .as("The description is displayed correctly"); } - @Test - public void abortCreate() { + @Feature(summary = "The administrator can cancel creating a new " + + "translation memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void abortCreate() throws Exception { String abortName = "aborttmtest"; String abortDescription = "abort tm description"; - TranslationMemoryPage translationMemoryPage = - new BasicWorkFlow().goToHome().goToAdministration() - .goToTranslationMemoryPage().clickCreateNew() - .enterMemoryID(abortName) - .enterMemoryDescription(abortDescription).cancelTM(); - - assertThat("The Translation Memory was not created", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.not(Matchers.hasItem(abortName))); + TranslationMemoryPage translationMemoryPage = new BasicWorkFlow() + .goToHome() + .goToAdministration() + .goToTranslationMemoryPage() + .clickCreateNew() + .enterMemoryID(abortName) + .enterMemoryDescription(abortDescription) + .cancelTM(); + + assertThat(translationMemoryPage.getListedTranslationMemorys()) + .doesNotContain(abortName) + .as("The Translation Memory was not created"); } - @Test - public void translationMemoryIdsAreUnique() { + @Feature(summary = "The administrator must use a unique identifier to " + + "create a new translation memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void translationMemoryIdsAreUnique() throws Exception { String nonUniqueTMId = "doubletmtest"; - String nameError = "This Id is not available"; - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow() - .createTranslationMemory(nonUniqueTMId); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(nonUniqueTMId); - assertThat("The new Translation Memory is listed", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.hasItem(nonUniqueTMId)); + assertThat(tmMemoryPage.getListedTranslationMemorys()) + .contains(nonUniqueTMId) + .as("The new Translation Memory is listed"); - TranslationMemoryEditPage translationMemoryEditPage = - translationMemoryPage.clickCreateNew() - .enterMemoryID(nonUniqueTMId) - .enterMemoryDescription("Meh"); + TranslationMemoryEditPage translationMemoryEditPage = tmMemoryPage + .clickCreateNew() + .enterMemoryID(nonUniqueTMId) + .enterMemoryDescription("Meh") + .clickSaveAndExpectFailure(); - assertThat("The Id Is Not Available error is displayed", - translationMemoryEditPage.waitForErrors(), - Matchers.hasItem(nameError)); + assertThat(translationMemoryEditPage.waitForErrors()) + .contains(TranslationMemoryPage.ID_UNAVAILABLE) + .as("The Id Is Not Available error is displayed"); - translationMemoryEditPage = - translationMemoryEditPage.clickSaveAndExpectFailure(); + translationMemoryEditPage = translationMemoryEditPage + .clickSaveAndExpectFailure(); translationMemoryEditPage.assertNoCriticalErrors(); // RHBZ-1010771 - assertThat("The Id Is Not Available error is displayed", - translationMemoryEditPage.waitForErrors(), - Matchers.hasItem(nameError)); + assertThat(translationMemoryEditPage.waitForErrors()) + .contains(TranslationMemoryPage.ID_UNAVAILABLE) + .as("The Id Is Not Available error is displayed"); } - @Test - public void importTranslationMemory() { + @Feature(summary = "The administrator can import data from a tmx data " + + "file into a translation memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void importTranslationMemory() throws Exception { String importTMId = "importmtest"; - File importFile = - testFileGenerator - .generateTestFileWithContent( - "importtmtest", - ".tmx", - "\n" - + "\n" - + "\n" - + "
\n" - + " \n" - + "Fedora is an open, innovative, forward looking operating system and platform, based on Linux, that is always free for anyone to use, modify and distribute, now and forever. It is developed by a large community of people who strive to provide and maintain the very best in free, open source software and standards. Fedora is part of the Fedora Project, sponsored by Red Hat, Inc.This is a TM Import Test\n" - + " \n" + ""); + File importFile = testFileGenerator.openTestFile("test-tmx.xml"); - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow() - .createTranslationMemory(importTMId) - .clickImport(importTMId) - .enterImportFileName(importFile.getAbsolutePath()) - .clickUploadButtonAndAcknowledge(); - - assertThat("The Translation Memory has one entry", - translationMemoryPage.getNumberOfEntries(importTMId), - Matchers.equalTo("1")); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(importTMId) + .clickImport(importTMId) + .enterImportFileName(importFile.getAbsolutePath()) + .clickUploadButtonAndAcknowledge(); + assertThat(tmMemoryPage.getNumberOfEntries(importTMId)).isEqualTo("1") + .as("The Translation Memory has one entry"); } - @Test - public void rejectEmptyTranslation() { + @Feature(summary = "The system rejects empty TMX data files", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void rejectEmptyTranslation() throws Exception { String rejectTMId = "rejectemptytmtest"; - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow().createTranslationMemory( - rejectTMId).clickImport(rejectTMId); - Alert uploadError = translationMemoryPage.expectFailedUpload(); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(rejectTMId) + .clickImport(rejectTMId); + Alert uploadError = tmMemoryPage.expectFailedUpload(); - assertThat("Error is displayed", uploadError.getText(), - Matchers.startsWith("There was an error uploading the file")); + assertThat(uploadError.getText() + .startsWith(TranslationMemoryPage.UPLOAD_ERROR)).isTrue() + .as("Error is displayed"); - translationMemoryPage = translationMemoryPage.dismissError(); + tmMemoryPage = tmMemoryPage.dismissError(); - assertThat("No change is recorded", - translationMemoryPage.getNumberOfEntries(rejectTMId), - Matchers.equalTo("0")); + assertThat(tmMemoryPage.getNumberOfEntries(rejectTMId)).isEqualTo("0") + .as("No change is recorded"); } - @Test - public void deleteTranslationMemory() { + @Feature(summary = "The administrator can delete a translation memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void deleteTranslationMemory() throws Exception { String deleteTMId = "deletetmtest"; - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow() - .createTranslationMemory(deleteTMId); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(deleteTMId); - assertThat("The new Translation Memory is listed", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.hasItem(deleteTMId)); + assertThat(tmMemoryPage.getListedTranslationMemorys()) + .contains(deleteTMId) + .as("The new Translation Memory is listed"); - translationMemoryPage = - translationMemoryPage.clickDeleteTmAndAccept(deleteTMId); + tmMemoryPage = tmMemoryPage.clickDeleteTmAndAccept(deleteTMId); - assertThat("The new Translation Memory is no longer listed", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.not(Matchers.hasItem(deleteTMId))); + assertThat(tmMemoryPage.getListedTranslationMemorys()) + .doesNotContain(deleteTMId) + .as("The new Translation Memory is no longer listed"); } - @Test - public void dontDeleteTranslationMemory() { + @Feature(summary = "The administrator can cancel the delete of a " + + "translation memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void dontDeleteTranslationMemory() throws Exception { String dontDeleteTMId = "dontdeletetmtest"; - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow() - .createTranslationMemory(dontDeleteTMId); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(dontDeleteTMId); - assertThat("The new Translation Memory is listed", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.hasItem(dontDeleteTMId)); + assertThat(tmMemoryPage.getListedTranslationMemorys()) + .contains(dontDeleteTMId) + .as("The new Translation Memory is listed"); - translationMemoryPage = - translationMemoryPage.clickDeleteTmAndCancel(dontDeleteTMId); + tmMemoryPage = tmMemoryPage.clickDeleteTmAndCancel(dontDeleteTMId); - assertThat("The new Translation Memory is still listed", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.hasItem(dontDeleteTMId)); + assertThat(tmMemoryPage.getListedTranslationMemorys()) + .contains(dontDeleteTMId) + .as("The new Translation Memory is still listed"); } - @Test - public void clearTranslationMemory() { + @Feature(summary = "The administrator can clear the content of a " + + "translation memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void clearTranslationMemory() throws Exception { String clearTMId = "cleartmtest"; - File importFile = - testFileGenerator - .generateTestFileWithContent( - "cleartmtest", - ".tmx", - "\n" - + "\n" - + "\n" - + "
\n" - + " \n" - + "Fedora is an open, innovative, forward looking operating system and platform, based on Linux, that is always free for anyone to use, modify and distribute, now and forever. It is developed by a large community of people who strive to provide and maintain the very best in free, open source software and standards. Fedora is part of the Fedora Project, sponsored by Red Hat, Inc.This is a TM Import Test\n" - + " \n" + ""); + File importFile = testFileGenerator.openTestFile("test-tmx.xml"); - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow() - .createTranslationMemory(clearTMId) - .clickImport(clearTMId) - .enterImportFileName(importFile.getAbsolutePath()) - .clickUploadButtonAndAcknowledge(); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(clearTMId) + .clickImport(clearTMId) + .enterImportFileName(importFile.getAbsolutePath()) + .clickUploadButtonAndAcknowledge(); - assertThat("The TM has one item", - translationMemoryPage.getNumberOfEntries(clearTMId), - Matchers.equalTo("1")); + assertThat(tmMemoryPage.getNumberOfEntries(clearTMId)).isEqualTo("1") + .as("The TM has one item"); - translationMemoryPage = - translationMemoryPage.clickClearTMAndAccept(clearTMId); + tmMemoryPage = tmMemoryPage.clickClearTMAndAccept(clearTMId); - assertThat("The translation memory entries is empty", - translationMemoryPage.waitForExpectedNumberOfEntries(clearTMId, - "0"), Matchers.equalTo("0")); + assertThat(tmMemoryPage.waitForExpectedNumberOfEntries(clearTMId, "0")) + .isEqualTo("0") + .as("The translation memory entries is empty"); } - @Test - public void dontClearTranslationMemory() { + @Feature(summary = "The administrator can cancel clearing the content " + + "of a translation memory entry", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void dontClearTranslationMemory() throws Exception { String clearTMId = "dontcleartmtest"; - File importFile = - testFileGenerator - .generateTestFileWithContent( - "cleartmtest", - ".tmx", - "\n" - + "\n" - + "\n" - + "
\n" - + " \n" - + "Fedora is an open, innovative, forward looking operating system and platform, based on Linux, that is always free for anyone to use, modify and distribute, now and forever. It is developed by a large community of people who strive to provide and maintain the very best in free, open source software and standards. Fedora is part of the Fedora Project, sponsored by Red Hat, Inc.This is a TM Import Test\n" - + " \n" + ""); + File importFile = testFileGenerator.openTestFile("test-tmx.xml"); - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow() - .createTranslationMemory(clearTMId) - .clickImport(clearTMId) - .enterImportFileName(importFile.getAbsolutePath()) - .clickUploadButtonAndAcknowledge(); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(clearTMId) + .clickImport(clearTMId) + .enterImportFileName(importFile.getAbsolutePath()) + .clickUploadButtonAndAcknowledge(); - assertThat("The TM has one item", - translationMemoryPage.getNumberOfEntries(clearTMId), - Matchers.equalTo("1")); + assertThat(tmMemoryPage.getNumberOfEntries(clearTMId)).isEqualTo("1") + .as("The TM has one item"); - translationMemoryPage = - translationMemoryPage.clickClearTMAndCancel(clearTMId); + tmMemoryPage = tmMemoryPage.clickClearTMAndCancel(clearTMId); - assertThat("The translation memory entries count is the same", - translationMemoryPage.getNumberOfEntries(clearTMId), - Matchers.equalTo("1")); + assertThat(tmMemoryPage.getNumberOfEntries(clearTMId)).isEqualTo("1") + .as("The translation memory entries count is the same"); } - @Test - public void mustClearBeforeDelete() { + @Feature(summary = "The administrator must clear a translation memory " + + "entry before it can be deleted", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void mustClearBeforeDelete() throws Exception { String forceClear = "forcecleartodelete"; - File importFile = - testFileGenerator - .generateTestFileWithContent( - "cleartmtest", - ".tmx", - "\n" - + "\n" - + "\n" - + "
\n" - + " \n" - + "Fedora is an open, innovative, forward looking operating system and platform, based on Linux, that is always free for anyone to use, modify and distribute, now and forever. It is developed by a large community of people who strive to provide and maintain the very best in free, open source software and standards. Fedora is part of the Fedora Project, sponsored by Red Hat, Inc.This is a TM Import Test\n" - + " \n" + ""); - - TranslationMemoryPage translationMemoryPage = - new TranslationMemoryWorkFlow() - .createTranslationMemory(forceClear) - .clickImport(forceClear) - .enterImportFileName(importFile.getAbsolutePath()) - .clickUploadButtonAndAcknowledge(); + File importFile = testFileGenerator.openTestFile("test-tmx.xml"); - assertThat("The TM has one item", - translationMemoryPage.getNumberOfEntries(forceClear), - Matchers.equalTo("1")); + TranslationMemoryPage tmMemoryPage = new TranslationMemoryWorkFlow() + .createTranslationMemory(forceClear) + .clickImport(forceClear) + .enterImportFileName(importFile.getAbsolutePath()) + .clickUploadButtonAndAcknowledge(); - assertThat("The item cannot yet be deleted", - !translationMemoryPage.canDelete(forceClear)); + assertThat(tmMemoryPage.getNumberOfEntries(forceClear)).isEqualTo("1") + .as("The TM has one item"); + assertThat(tmMemoryPage.canDelete(forceClear)).isFalse() + .as("The item cannot yet be deleted"); - translationMemoryPage = - translationMemoryPage.clickClearTMAndAccept(forceClear); - translationMemoryPage.waitForExpectedNumberOfEntries(forceClear, "0"); + tmMemoryPage = tmMemoryPage.clickClearTMAndAccept(forceClear); + tmMemoryPage.waitForExpectedNumberOfEntries(forceClear, "0"); - assertThat("The item can be deleted", - translationMemoryPage.canDelete(forceClear)); + assertThat(tmMemoryPage.canDelete(forceClear)).isTrue() + .as("The item can be deleted"); - translationMemoryPage = - translationMemoryPage.clickDeleteTmAndAccept(forceClear); + tmMemoryPage = tmMemoryPage.clickDeleteTmAndAccept(forceClear); - assertThat("The item is deleted", - translationMemoryPage.getListedTranslationMemorys(), - Matchers.not(Matchers.hasItem(forceClear))); + assertThat(tmMemoryPage.getListedTranslationMemorys()) + .doesNotContain(forceClear) + .as("The item is deleted"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/administration/ManageSearchTest.java b/functional-test/src/test/java/org/zanata/feature/administration/ManageSearchTest.java index 8cada5b8f4..40bb58fe17 100644 --- a/functional-test/src/test/java/org/zanata/feature/administration/ManageSearchTest.java +++ b/functional-test/src/test/java/org/zanata/feature/administration/ManageSearchTest.java @@ -25,6 +25,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.administration.ManageSearchPage; @@ -32,7 +33,7 @@ import org.zanata.util.SampleProjectRule; import org.zanata.workflow.LoginWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; @Category(DetailedTest.class) public class ManageSearchTest extends ZanataTestCase { @@ -47,47 +48,53 @@ public void before() { dashboardPage = new LoginWorkFlow().signIn("admin", "admin"); } - @Test - public void regenerateSearchIndexes() { + @Feature(summary = "The administrator can clear and regenerate all of the " + + "search indexes", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void regenerateSearchIndexes() throws Exception { ManageSearchPage manageSearchPage = dashboardPage .goToAdministration() .goToManageSeachPage() .clickSelectAll(); - assertThat("All actions are selected", - manageSearchPage.allActionsSelected()); - assertThat("No operations are running", - manageSearchPage.noOperationsRunningIsDisplayed()); + assertThat(manageSearchPage.allActionsSelected()) + .as("All actions are selected"); + assertThat(manageSearchPage.noOperationsRunningIsDisplayed()) + .as("No operations are running"); manageSearchPage = manageSearchPage .performSelectedActions() .waitForActionsToFinish(); - assertThat("Completed is displayed", - manageSearchPage.completedIsDisplayed()); + assertThat(manageSearchPage.completedIsDisplayed()) + .as("Completed is displayed"); - assertThat("No operations are running", - manageSearchPage.noOperationsRunningIsDisplayed()); + assertThat(manageSearchPage.noOperationsRunningIsDisplayed()) + .as("No operations are running"); } - @Test + @Feature(summary = "The administrator can abort the regeneration of the " + + "search indexes", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) @Ignore("Data set not large enough to achieve stable test") - public void abortReindexes() { + public void abortReindexes() throws Exception { ManageSearchPage manageSearchPage = dashboardPage .goToAdministration() .goToManageSeachPage() .clickSelectAll(); - assertThat("All actions are selected", - manageSearchPage.allActionsSelected()); - assertThat("No operations are running", - manageSearchPage.noOperationsRunningIsDisplayed()); + assertThat(manageSearchPage.allActionsSelected()) + .as("All actions are selected"); + assertThat(manageSearchPage.noOperationsRunningIsDisplayed()) + .as("No operations are running"); manageSearchPage = manageSearchPage .performSelectedActions() .abort(); - assertThat("Aborted is displayed", - manageSearchPage.abortedIsDisplayed()); + assertThat(manageSearchPage.abortedIsDisplayed()) + .as("Aborted is displayed"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/administration/ManageUsersFullTest.java b/functional-test/src/test/java/org/zanata/feature/administration/ManageUsersFullTest.java deleted file mode 100644 index 2236e03791..0000000000 --- a/functional-test/src/test/java/org/zanata/feature/administration/ManageUsersFullTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2013, Red Hat, Inc. and individual contributors as indicated by the - * @author tags. See the copyright.txt file in the distribution for a full - * listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this software; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF - * site: http://www.fsf.org. - */ -package org.zanata.feature.administration; - -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.zanata.feature.testharness.ZanataTestCase; -import org.zanata.feature.testharness.TestPlan.DetailedTest; -import org.zanata.page.administration.ManageUserAccountPage; -import org.zanata.page.administration.ManageUserPage; -import org.zanata.page.dashboard.DashboardBasePage; -import org.zanata.util.AddUsersRule; -import org.zanata.util.HasEmailRule; -import org.zanata.workflow.LoginWorkFlow; - -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * @author Damian Jansen djansen@redhat.com - */ -@Category(DetailedTest.class) -public class ManageUsersFullTest extends ZanataTestCase { - - @Rule - public AddUsersRule addUsersRule = new AddUsersRule(); - @ClassRule - public static HasEmailRule emailRule = new HasEmailRule(); - - private DashboardBasePage dashboardPage; - - @Before - public void before() { - dashboardPage = new LoginWorkFlow().signIn("admin", "admin"); - } - - @Test - public void changeAUsersUsername() { - String username = "administratornamechange"; - ManageUserPage manageUserPage = - dashboardPage.goToAdministration().goToManageUserPage(); - - ManageUserAccountPage manageUserAccountPage = - manageUserPage.editUserAccount("admin"); - manageUserPage = - manageUserAccountPage.clearFields().enterUsername(username) - .saveUser(); - assertThat("Administrator is displayed", manageUserPage.getUserList(), - Matchers.hasItem(username)); - } - -} diff --git a/functional-test/src/test/java/org/zanata/feature/administration/ManageUsersTest.java b/functional-test/src/test/java/org/zanata/feature/administration/ManageUsersTest.java new file mode 100644 index 0000000000..22841ee811 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/administration/ManageUsersTest.java @@ -0,0 +1,137 @@ +/* + * Copyright 2013, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.feature.administration; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; +import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.page.account.SignInPage; +import org.zanata.page.administration.ManageUserAccountPage; +import org.zanata.page.dashboard.DashboardBasePage; +import org.zanata.util.AddUsersRule; +import org.zanata.util.HasEmailRule; +import org.zanata.workflow.BasicWorkFlow; +import org.zanata.workflow.LoginWorkFlow; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Damian Jansen djansen@redhat.com + */ +@Category(DetailedTest.class) +public class ManageUsersTest extends ZanataTestCase { + + @Rule + public AddUsersRule addUsersRule = new AddUsersRule(); + + @ClassRule + public static HasEmailRule emailRule = new HasEmailRule(); + + private DashboardBasePage dashboardPage; + + @Before + public void before() { + dashboardPage = new LoginWorkFlow().signIn("admin", "admin"); + } + + @Feature(summary = "The administrator can change a user's password", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeAUsersPassword() throws Exception { + dashboardPage.goToAdministration() + .goToManageUserPage() + .editUserAccount("translator") + .enterPassword("newpassword") + .enterConfirmPassword("newpassword") + .saveUser() + .logout(); + + dashboardPage = new LoginWorkFlow().signIn("translator", "newpassword"); + + assertThat(dashboardPage.loggedInAs()) + .isEqualTo("translator") + .as("User logged in with new password"); + } + + @Feature(summary = "The administrator must enter the new user password " + + "into password and confirm password in order to change it", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeAUsersPasswordRequiredFields() throws Exception { + ManageUserAccountPage manageUserAccountPage = dashboardPage + .goToAdministration() + .goToManageUserPage() + .editUserAccount("translator") + .enterPassword("newpassword") + .saveUserExpectFailure(); + + assertThat(manageUserAccountPage.getErrors()) + .contains(ManageUserAccountPage.PASSWORD_ERROR) + .as("The password failure error is displayed"); + } + + @Feature(summary = "The administrator can disable an account", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void disableAUsersAccount() throws Exception { + dashboardPage.goToAdministration() + .goToManageUserPage() + .editUserAccount("translator") + .clickEnabled() + .saveUser() + .logout(); + + SignInPage signInPage = new BasicWorkFlow() + .goToHome() + .clickSignInLink() + .enterUsername("translator") + .enterPassword("translator") + .clickSignInExpectError(); + assertThat(signInPage.getFieldErrors()) + .contains(SignInPage.LOGIN_FAILED_ERROR) + .as("The user's account cannot be logged in"); + } + + @Feature(summary = "The administrator can change a user account's roles", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeUserRoles() throws Exception { + dashboardPage.goToAdministration() + .goToManageUserPage() + .editUserAccount("translator") + .clickRole("admin") + .saveUser() + .logout(); + + DashboardBasePage dashboardBasePage = new LoginWorkFlow() + .signIn("translator", "translator"); + + assertThat(dashboardBasePage.goToAdministration().getTitle()) + .isEqualTo("Zanata: Administration") + .as("The user can access the administration panel"); + } +} diff --git a/functional-test/src/test/java/org/zanata/feature/clientserver/GettextPluralSupportTest.java b/functional-test/src/test/java/org/zanata/feature/clientserver/GettextPluralSupportTest.java index ca523553ac..e7405e67bb 100644 --- a/functional-test/src/test/java/org/zanata/feature/clientserver/GettextPluralSupportTest.java +++ b/functional-test/src/test/java/org/zanata/feature/clientserver/GettextPluralSupportTest.java @@ -6,15 +6,14 @@ import java.io.IOException; import java.util.List; -import org.hamcrest.Matchers; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.xml.sax.InputSource; import org.zanata.adapter.po.PoReader2; import org.zanata.common.LocaleId; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; @@ -28,7 +27,7 @@ import org.zanata.workflow.LoginWorkFlow; import com.google.common.io.Files; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * This covers TCMS case output = @@ -80,7 +80,7 @@ public void canPushAndPullPlural() throws IOException { "mvn -B zanata:push -Dzanata.pushType=both -Dzanata.userConfig=" + userConfigPath); - assertThat(client.isPushSuccessful(output), Matchers.is(true)); + assertThat(client.isPushSuccessful(output)).isTrue(); EditorPage editorPage = verifyPluralPushedToEditor(); @@ -91,21 +91,21 @@ public void canPushAndPullPlural() throws IOException { + pullDirPath + " -Dzanata.transDir=" + pullDirPath + " -Dzanata.userConfig=" + userConfigPath; output = client.callWithTimeout(tempDir, command); - assertThat(client.isPushSuccessful(output), Matchers.is(true)); + assertThat(client.isPushSuccessful(output)).isTrue(); // source round trip List originalTextFlows = getTextFlows(new File(projectRootPath + "/pot/test.pot")); List pulledTextFlows = getTextFlows(new File(pullDir, "test.pot")); - assertThat(pulledTextFlows, Matchers.equalTo(originalTextFlows)); + assertThat(pulledTextFlows).isEqualTo(originalTextFlows); // translation round trip List originalTargets = getTextFlowTargets(new File(projectRootPath + "/pl/test.po")); List pulledTargets = getTextFlowTargets(new File(pullDir + "/pl/test.po")); - assertThat(pulledTargets, Matchers.equalTo(originalTargets)); + assertThat(pulledTargets).isEqualTo(originalTargets); // translate on web UI and pull again editorPage.translateTargetAtRowIndex(0, "one aoeuaouaou") @@ -116,7 +116,7 @@ public void canPushAndPullPlural() throws IOException { List newContents = getTextFlowTargets(new File(pullDir + "/pl/test.po")).get(0) .getContents(); - assertThat(newContents, Matchers.hasItem("one aoeuaouaou")); + assertThat(newContents).contains("one aoeuaouaou"); } @@ -124,20 +124,23 @@ private static EditorPage verifyPluralPushedToEditor() { // verify first message new LoginWorkFlow().signIn("admin", "admin"); EditorPage editorPage = new BasicWorkFlow() - .goToEditor("plurals", "master", "pl", "test") - .setSyntaxHighlighting(true); + .goToEditor("plurals", "master", "pl", "test"); - assertThat(editorPage.getMessageSourceAtRowIndex(0, Plurals.SourceSingular), - Matchers.equalTo("One file removed")); - assertThat(editorPage.getMessageSourceAtRowIndex(0, Plurals.SourcePlural), - Matchers.equalTo("%d files removed")); + assertThat(editorPage.getMessageSourceAtRowIndex(0, Plurals.SourceSingular)) + .isEqualTo("One file removed"); + assertThat(editorPage.getMessageSourceAtRowIndex(0, Plurals.SourcePlural)) + .isEqualTo("%d files removed"); // nplural for Polish is 3 - assertThat(editorPage.getMessageTargetAtRowIndex(0, Plurals.TargetSingular), - Matchers.equalTo("1 aoeuaouaou")); - assertThat(editorPage.getMessageTargetAtRowIndex(0, Plurals.TargetPluralOne), - Matchers.equalTo("%d aoeuaouao")); - assertThat(editorPage.getMessageTargetAtRowIndex(0, Plurals.TargetPluralTwo), - Matchers.equalTo(" ")); + + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0, + Plurals.TargetSingular)) + .isEqualTo("1 aoeuaouaou"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0, + Plurals.TargetPluralOne)) + .isEqualTo("%d aoeuaouao"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0, + Plurals.TargetPluralTwo)) + .isEqualTo(""); return editorPage; } diff --git a/functional-test/src/test/java/org/zanata/feature/clientserver/ProjectMaintainerTest.java b/functional-test/src/test/java/org/zanata/feature/clientserver/ProjectMaintainerTest.java index f0f397e8f8..75de3b8efe 100644 --- a/functional-test/src/test/java/org/zanata/feature/clientserver/ProjectMaintainerTest.java +++ b/functional-test/src/test/java/org/zanata/feature/clientserver/ProjectMaintainerTest.java @@ -4,11 +4,11 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.io.Files; -import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.zanata.common.LocaleId; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projectversion.VersionLanguagesPage; @@ -24,7 +24,7 @@ import java.io.IOException; import java.util.List; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.TestFileGenerator.generateZanataXml; import static org.zanata.util.TestFileGenerator.makePropertiesFile; import static org.zanata.util.ZanataRestCaller.buildTextFlowTarget; @@ -51,11 +51,9 @@ public boolean accept(File dir, String name) { } }; - /** - * TCMS test case 91146 - */ - @Test + @Feature(summary = "A non-maintainer user may not push to a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 91146) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void nonProjectMaintainerCanNotPush() { // admin creates the project ZanataRestCaller adminRestCaller = new ZanataRestCaller(); @@ -68,15 +66,12 @@ public void nonProjectMaintainerCanNotPush() { + translatorConfig); String joinedOutput = Joiner.on("\n").skipNulls().join(output); - assertThat(joinedOutput, - Matchers.containsString("Authorization check failed")); + assertThat(joinedOutput).contains("Authorization check failed"); } - /** - * TCMS test case 91869 - */ - @Test + @Feature(summary = "The system will run CopyTrans when a push occurs", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 91869) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void pushTransAndCopyTransTest() { // translator creates the project and become maintainer ZanataRestCaller restCaller = @@ -88,15 +83,15 @@ public void pushTransAndCopyTransTest() { "mvn -B zanata:push -Dzanata.copyTrans=false -Dzanata.userConfig=" + translatorConfig); - assertThat(client.isPushSuccessful(output), Matchers.is(true)); + assertThat(client.isPushSuccessful(output)).isTrue(); new LoginWorkFlow().signIn("admin", "admin"); VersionLanguagesPage versionPage = new BasicWorkFlow().goToPage(String.format( PROJECT_VERSION_TEMPLATE, "plurals", "master"), VersionLanguagesPage.class); - assertThat(versionPage.getStatisticsForLocale("pl"), - Matchers.containsString("0.0%")); + assertThat(versionPage.getStatisticsForLocale("pl")) + .contains("0.0%"); // push trans client.callWithTimeout( @@ -105,8 +100,7 @@ public void pushTransAndCopyTransTest() { + translatorConfig); versionPage.reload(); - assertThat(versionPage.getStatisticsForLocale("pl"), - Matchers.containsString("6.0%")); + assertThat(versionPage.getStatisticsForLocale("pl")).contains("6.0%"); // create new version restCaller.createProjectAndVersion("plurals", "beta", "podir"); @@ -126,15 +120,12 @@ public void pushTransAndCopyTransTest() { PROJECT_VERSION_TEMPLATE, "plurals", "beta"), VersionLanguagesPage.class); - assertThat(betaVersionPage.getStatisticsForLocale("pl"), - Matchers.containsString("6.0%")); + assertThat(betaVersionPage.getStatisticsForLocale("pl")).contains("6.0%"); } - /** - * TCMS test case 136564 - */ - @Test + @Feature(summary = "A maintainer user may pull translations from a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 136564) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void projectMaintainerPullTest() throws IOException { ZanataRestCaller restCaller = new ZanataRestCaller("translator", @@ -172,7 +163,7 @@ public void projectMaintainerPullTest() throws IOException { client.callWithTimeout(workDir, "mvn -B org.zanata:zanata-maven-plugin:pull -DdryRun -Dzanata.userConfig=" + translatorConfig + " -Dzanata.transDir=" + transDir); - assertThat(transDir.listFiles(propFilter), Matchers.arrayWithSize(0)); + assertThat(transDir.listFiles(propFilter).length).isEqualTo(0); // create skeletons is false will only pull translated files client.callWithTimeout( @@ -182,8 +173,8 @@ public void projectMaintainerPullTest() throws IOException { + " -Dzanata.transDir=" + transDir.getAbsolutePath()); - assertThat(transDir.listFiles(propFilter), Matchers.arrayContaining(new File( - transDir, "prop1_pl.properties"))); + assertThat(transDir.listFiles(propFilter)).contains(new File( + transDir, "prop1_pl.properties")); // pull both client.callWithTimeout( @@ -193,13 +184,12 @@ public void projectMaintainerPullTest() throws IOException { + " -Dzanata.transDir=" + transDir.getAbsolutePath()); - assertThat(transDir.listFiles(propFilter), - Matchers.arrayContainingInAnyOrder(new File(transDir, - "prop1_pl.properties"))); + assertThat(transDir.listFiles(propFilter)).contains(new File(transDir, + "prop1_pl.properties")); // @formatter:off - assertThat(workDir.listFiles(propFilter), Matchers.arrayContainingInAnyOrder( + assertThat(workDir.listFiles(propFilter)).contains( new File(workDir, "prop1.properties"), - new File(workDir, "prop2.properties"))); + new File(workDir, "prop2.properties")); // @formatter:on } diff --git a/functional-test/src/test/java/org/zanata/feature/clientserver/PropertiesRoundTripTest.java b/functional-test/src/test/java/org/zanata/feature/clientserver/PropertiesRoundTripTest.java index 583ed1c6f3..58fb5d6297 100644 --- a/functional-test/src/test/java/org/zanata/feature/clientserver/PropertiesRoundTripTest.java +++ b/functional-test/src/test/java/org/zanata/feature/clientserver/PropertiesRoundTripTest.java @@ -7,11 +7,11 @@ import java.util.List; import org.fedorahosted.openprops.Properties; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; @@ -24,12 +24,9 @@ import com.google.common.collect.Lists; import com.google.common.io.Files; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** - * This will cover TCMS case 139837 - * * @author Patrick Huang pahuang@redhat.com */ @@ -59,61 +56,59 @@ public void setUp() throws IOException { properties.store(new FileWriter(propertiesSource), "comment"); } - @Test + @Feature(summary = "The maintainer user may push and pull properties files", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 139837) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void canPushAndPullProperties() throws IOException, InterruptedException { restCaller.createProjectAndVersion("properties-test", "master", "properties"); // generate a zanata.xml - TestFileGenerator.generateZanataXml(new File(tempDir, - "zanata.xml"), "properties-test", "master", "properties", Lists + TestFileGenerator.generateZanataXml(new File(tempDir, "zanata.xml"), + "properties-test", "master", "properties", Lists .newArrayList("pl")); - List output = - client.callWithTimeout(tempDir, - "mvn -B org.zanata:zanata-maven-plugin:push -Dzanata.srcDir=. -Dzanata.userConfig=" - + userConfigPath); + List output = client.callWithTimeout(tempDir, + "mvn -B org.zanata:zanata-maven-plugin:push -Dzanata.srcDir=. "+ + "-Dzanata.userConfig=" + userConfigPath); - assertThat(client.isPushSuccessful(output), Matchers.equalTo(true)); + assertThat(client.isPushSuccessful(output)).isTrue(); - EditorPage editorPage = verifyPushedToEditor() - .setSyntaxHighlighting(false); - editorPage = - editorPage.translateTargetAtRowIndex(2, - "translation updated approved") - .approveTranslationAtRow(2); + EditorPage editorPage = verifyPushedToEditor(); + editorPage = editorPage.translateTargetAtRowIndex(2, + "translation updated approved") + .approveTranslationAtRow(2); editorPage.translateTargetAtRowIndex(1, "translation updated fuzzy") .saveAsFuzzyAtRow(1); - output = - client.callWithTimeout(tempDir, - "mvn -B org.zanata:zanata-maven-plugin:pull -Dzanata.userConfig=" - + userConfigPath); + output = client.callWithTimeout(tempDir, + "mvn -B org.zanata:zanata-maven-plugin:pull " + + "-Dzanata.userConfig=" + userConfigPath); - assertThat(client.isPushSuccessful(output), Matchers.is(true)); + assertThat(client.isPushSuccessful(output)).isTrue(); File transFile = new File(tempDir, "test_pl.properties"); - assertThat(transFile.exists(), Matchers.is(true)); + assertThat(transFile.exists()).isTrue(); Properties translations = new Properties(); translations.load(new FileReader(transFile)); - assertThat(translations.size(), Matchers.is(1)); - assertThat(translations.getProperty("hey"), - Matchers.equalTo("translation updated approved")); + assertThat(translations.size()).isEqualTo(1); + assertThat(translations.getProperty("hey")) + .isEqualTo("translation updated approved"); // change on client side translations.setProperty("greeting", "translation updated on client"); translations.store(new FileWriter(transFile), null); // push again - client.callWithTimeout( - tempDir, - "mvn -B org.zanata:zanata-maven-plugin:push -Dzanata.pushType=trans -Dzanata.srcDir=. -Dzanata.userConfig=" - + userConfigPath); + client.callWithTimeout(tempDir, + "mvn -B org.zanata:zanata-maven-plugin:push " + + "-Dzanata.pushType=trans -Dzanata.srcDir=. -Dzanata.userConfig=" + + userConfigPath); final EditorPage editor = new BasicWorkFlow().goToEditor("properties-test", "master", "pl", "test"); - assertThat(editor.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("translation updated on client")); + assertThat(editor.getBasicTranslationTargetAtRowIndex(1)) + .isEqualTo("translation updated on client"); } private static EditorPage verifyPushedToEditor() { @@ -122,12 +117,12 @@ private static EditorPage verifyPushedToEditor() { new BasicWorkFlow().goToEditor("properties-test", "master", "pl", "test"); - assertThat(editorPage.getMessageSourceAtRowIndex(0), - Matchers.equalTo("hello world")); - assertThat(editorPage.getMessageSourceAtRowIndex(1), - Matchers.equalTo("this is from Huston")); - assertThat(editorPage.getMessageSourceAtRowIndex(2), - Matchers.equalTo("hey hey")); + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("hello world"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("this is from Huston"); + assertThat(editorPage.getMessageSourceAtRowIndex(2)) + .isEqualTo("hey hey"); return editorPage; } diff --git a/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentAccessTest.java b/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentAccessTest.java index ac864b86c4..21d1e33b5b 100644 --- a/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentAccessTest.java +++ b/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentAccessTest.java @@ -9,10 +9,10 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; -import org.hamcrest.Matchers; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.rest.dto.resource.Resource; @@ -22,7 +22,7 @@ import com.google.common.base.Throwables; import com.google.common.collect.Lists; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.ZanataRestCaller.buildSourceResource; import static org.zanata.util.ZanataRestCaller.buildTextFlow; @@ -36,7 +36,10 @@ public class ConcurrentAccessTest extends ZanataTestCase { @ClassRule public static AddUsersRule addUsersRule = new AddUsersRule(); - @Test + @Feature(summary = "The system will handle concurrent document " + + "creation gracefully", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void concurrentDocumentCreationWillNotCauseHibernateException() throws InterruptedException { final String projectSlug = "project"; @@ -66,7 +69,7 @@ projectSlug, iterationSlug, buildResource(suffix), List expectedReturnCode = Collections.nCopies(threadCount, 201); - assertThat(result, Matchers.equalTo(expectedReturnCode)); + assertThat(result).isEqualTo(expectedReturnCode); } private static Resource buildResource(int suffix) { diff --git a/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentEditTest.java b/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentEditTest.java index 42b4dcdde8..6c8b134664 100644 --- a/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentEditTest.java +++ b/functional-test/src/test/java/org/zanata/feature/concurrentedit/ConcurrentEditTest.java @@ -1,13 +1,11 @@ package org.zanata.feature.concurrentedit; -import java.util.concurrent.Callable; - -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.zanata.common.LocaleId; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; @@ -19,7 +17,7 @@ import org.zanata.workflow.LoginWorkFlow; import lombok.extern.slf4j.Slf4j; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.ZanataRestCaller.buildSourceResource; import static org.zanata.util.ZanataRestCaller.buildTextFlow; import static org.zanata.util.ZanataRestCaller.buildTextFlowTarget; @@ -43,7 +41,10 @@ public void setUp() { restCaller = new ZanataRestCaller(); } - @Test + @Feature(summary = "The system will propagate translations done by " + + "upload and copyTrans to editor", + bugzilla = 1067253) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void editorReceivesRestServiceResults() { // create project and push source String projectSlug = "base"; @@ -69,7 +70,7 @@ public void editorReceivesRestServiceResults() { String translation = editorPage.getMessageTargetAtRowIndex(0); // for some reason getText() will return one space in it - assertThat(translation.trim(), Matchers.isEmptyString()); + assertThat(translation.trim()).isEmpty(); // push target TranslationsResource translationsResource = @@ -79,15 +80,14 @@ public void editorReceivesRestServiceResults() { new LocaleId("pl"), translationsResource, "auto"); // REST push broadcast event to editor - editorPage.waitFor(new Callable() { - @Override - public String call() throws Exception { - return editorPage.getBasicTranslationTargetAtRowIndex(0); - } - }, Matchers.equalTo("hello world translated")); + assertThat(editorPage.expectBasicTranslationAtRowIndex(0, + "hello world translated")).isTrue(); } - @Test + @Feature(summary = "The system will show concurrently changed " + + "translations to the web editor user", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void editorReceivesCopyTransResults() throws Exception { // create project and populate master version String projectSlug = "base"; @@ -124,18 +124,14 @@ public void editorReceivesCopyTransResults() throws Exception { String translation = editorPage.getMessageTargetAtRowIndex(0); // for some reason getText() will return one space in it - assertThat(translation.trim(), Matchers.isEmptyString()); + assertThat(translation.trim()).isEmpty(); // run copyTrans restCaller.runCopyTrans(projectSlug, "beta", docId); // copyTrans broadcast event to editor - editorPage.waitFor(new Callable() { - @Override - public String call() throws Exception { - return editorPage.getBasicTranslationTargetAtRowIndex(0); - } - }, Matchers.equalTo("hello world translated")); + assertThat(editorPage.expectBasicTranslationAtRowIndex(0, + "hello world translated")).isTrue(); } } diff --git a/functional-test/src/test/java/org/zanata/feature/dashboard/DashboardTest.java b/functional-test/src/test/java/org/zanata/feature/dashboard/DashboardTest.java index d2c5957e17..0f3509fc30 100644 --- a/functional-test/src/test/java/org/zanata/feature/dashboard/DashboardTest.java +++ b/functional-test/src/test/java/org/zanata/feature/dashboard/DashboardTest.java @@ -31,6 +31,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; import org.zanata.feature.testharness.TestPlan.DetailedTest; @@ -72,7 +73,9 @@ public void setUp() { dashboard = new LoginWorkFlow().signIn("admin", "admin"); } - @Test + @Feature(summary = "The user can traverse Dashboard activity lists", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) @Category(BasicAcceptanceTest.class) public void dashboardBasicTests() throws Exception { assertThat(dashboardPresentAfterLogin()) @@ -91,8 +94,7 @@ private boolean activityListExpands() throws Exception { DashboardActivityTab activityTab = dashboard.gotoActivityTab(); assertThat(activityTab.getMyActivityList()).isNotEmpty(); int initialActivitySize = activityTab.getMyActivityList().size(); - activityTab.clickMoreActivity(); - return activityTab.getMyActivityList().size() > initialActivitySize; + return activityTab.clickMoreActivity(); } private boolean projectListIsNotEmpty() throws Exception { @@ -100,30 +102,33 @@ private boolean projectListIsNotEmpty() throws Exception { return projectsTab.getMaintainedProjectList().size() > 0; } - @Test + @Feature(summary = "The user can change their email address", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void accountEmailModification() throws Exception { - final String successMessage = - "You will soon receive an email with a link to activate your email account change."; dashboard.goToSettingsTab() .gotoSettingsAccountTab() .typeNewAccountEmailAddress("new@fakeemail.com") .clickUpdateEmailButton(); - assertThat(dashboard.expectNotification(successMessage)); + assertThat(dashboard.expectNotification(DashboardBasePage.EMAIL_SENT)); } - @Test + @Feature(summary = "The user can change their password", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86823) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void passwordChange() throws Exception { - final String passwordChanged = - "Your password has been successfully changed."; dashboard.goToSettingsTab() .gotoSettingsAccountTab() .typeOldPassword("admin") .typeNewPassword("admin2") .clickUpdatePasswordButton(); - assertThat(dashboard.expectNotification(passwordChanged)); + assertThat(dashboard.expectNotification( + DashboardBasePage.PASSWORD_UPDATE_SUCCESS)); } - @Test + @Feature(summary = "The user can begin creating a project from the Dashboard", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void createProject() throws Exception { CreateProjectPage createProjectPage = dashboard.gotoProjectsTab().clickOnCreateProjectLink(); diff --git a/functional-test/src/test/java/org/zanata/feature/document/DocTypeUploadTest.java b/functional-test/src/test/java/org/zanata/feature/document/DocTypeUploadTest.java new file mode 100644 index 0000000000..915eb81702 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/document/DocTypeUploadTest.java @@ -0,0 +1,136 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.feature.document; + +import lombok.extern.slf4j.Slf4j; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.experimental.categories.Category; +import org.junit.experimental.theories.DataPoint; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.runner.RunWith; +import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; +import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.page.projectversion.VersionDocumentsPage; +import org.zanata.page.projectversion.VersionLanguagesPage; +import org.zanata.page.projectversion.versionsettings.VersionDocumentsTab; +import org.zanata.page.webtrans.EditorPage; +import org.zanata.util.CleanDocumentStorageRule; +import org.zanata.util.SampleProjectRule; +import org.zanata.util.TestFileGenerator; +import org.zanata.workflow.LoginWorkFlow; +import org.zanata.workflow.ProjectWorkFlow; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Damian Jansen + * djansen@redhat.com + */ +@Slf4j +@RunWith(Theories.class) +public class DocTypeUploadTest extends ZanataTestCase { + + @ClassRule + public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); + + @ClassRule + public static CleanDocumentStorageRule documentStorageRule = + new CleanDocumentStorageRule(); + + @BeforeClass + public static void beforeClass() { + new LoginWorkFlow().signIn("admin", "admin"); + new ProjectWorkFlow().createNewProjectVersion( + "about fedora", "doctype-upload", "File") + .logout(); + } + + private static String testString = "Test text 1"; + + @DataPoint + public static File SRT_FILE = new TestFileGenerator() + .generateTestFileWithContent( + "testsrtfile", ".srt", + "1" + sep() + "00:00:01,000 --> 00:00:02,000" + + sep() + testString); + + @DataPoint + public static File WEBVTT_FILE = new TestFileGenerator() + .generateTestFileWithContent( + "testvttfile", ".vtt", + "00:01.000 --> 00:01.000" + + sep() + testString); + + @DataPoint + public static File SBT_FILE = new TestFileGenerator() + .generateTestFileWithContent( + "testsbtfile", ".sbt", + "00:04:35.03,00:04:38.82" + + sep() + testString); + + @DataPoint + public static File SUB_FILE = new TestFileGenerator() + .generateTestFileWithContent( + "testsubfile", ".sub", + "00:04:35.03,00:04:38.82" + + sep() + testString); + + @Theory + @Category(BasicAcceptanceTest.class) + public void uploadFile(File testFile) throws Exception { + String testFileName = testFile.getName(); + log.info("[uploadFile] "+testFileName); + + VersionDocumentsPage versionDocumentsPage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("doctype-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(testFile.getAbsolutePath()) + .submitUpload() + .clickUploadDone() + .gotoDocumentTab(); + + assertThat(versionDocumentsPage.sourceDocumentsContains(testFileName)) + .as("Document shows in table"); + + EditorPage editorPage = versionDocumentsPage + .gotoLanguageTab() + .translate("pl", testFileName); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo(testString) + .as("The translation source is correct"); + } + + private static String sep() { + return System.getProperty("line.separator"); + } + +} diff --git a/functional-test/src/test/java/org/zanata/feature/document/HTMLDocumentTypeTest.java b/functional-test/src/test/java/org/zanata/feature/document/HTMLDocumentTypeTest.java index 6c1ba265c0..5c82671150 100644 --- a/functional-test/src/test/java/org/zanata/feature/document/HTMLDocumentTypeTest.java +++ b/functional-test/src/test/java/org/zanata/feature/document/HTMLDocumentTypeTest.java @@ -22,89 +22,140 @@ import java.io.File; -import org.hamcrest.Matchers; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projectversion.VersionDocumentsPage; -import org.zanata.page.projectversion.VersionLanguagesPage; +import org.zanata.page.projectversion.versionsettings.VersionDocumentsTab; import org.zanata.page.webtrans.EditorPage; -import org.zanata.util.CleanDocumentStorageRule; import org.zanata.util.SampleProjectRule; import org.zanata.util.TestFileGenerator; -import org.zanata.workflow.BasicWorkFlow; import org.zanata.workflow.LoginWorkFlow; +import org.zanata.page.projects.projectsettings.ProjectPermissionsTab; +import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.zanata.util.FunctionalTestHelper.assumeFalse; +import static org.assertj.core.api.Assertions.assertThat; /** - * @author Damian Jansen djansen@redhat.com + * @author Damian Jansen + * djansen@redhat.com */ @Category(DetailedTest.class) public class HTMLDocumentTypeTest extends ZanataTestCase { - @Rule - public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - - @Rule - public CleanDocumentStorageRule documentStorageRule = - new CleanDocumentStorageRule(); + @ClassRule + public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); private TestFileGenerator testFileGenerator = new TestFileGenerator(); - @Before - public void before() { - new BasicWorkFlow().goToHome().deleteCookiesAndRefresh(); - String documentStorageDirectory = - CleanDocumentStorageRule.getDocumentStoragePath() - .concat(File.separator).concat("documents") - .concat(File.separator); - assumeFalse("", new File(documentStorageDirectory).exists()); + @BeforeClass + public static void beforeClass() { + ProjectPermissionsTab projectPermissionsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsPermissionsTab() + .enterSearchMaintainer("translator") + .selectSearchMaintainer("translator"); + projectPermissionsTab.expectNotification( + "Maintainer \"translator\" has been added to project."); + projectPermissionsTab = projectPermissionsTab.clickRemoveOn("admin"); + projectPermissionsTab.expectNotification("Maintainer \"Administrator\" " + + "has been removed from project."); + new ProjectWorkFlow().createNewProjectVersion( + "about fedora", "html-upload", "File") + .logout(); } - @Test - public void uploadHTMLFile() { - File htmlfile = - testFileGenerator - .generateTestFileWithContent("testhtmlfile", ".html", - "Test content
This is Bold text"); + @Feature(bugzilla = 980670, + summary = "Administrator can upload a HTML file for translation", + tcmsTestCaseIds = { 377743 }, + tcmsTestPlanIds = { 5316 } ) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void uploadHTMLFileAsAdministrator() throws Exception { + File htmlfile = testFileGenerator.generateTestFileWithContent( + "testhtmlfile", ".html", + "Test content" + + "
This is Bold text"); String testFileName = htmlfile.getName(); - String successfullyUploaded = "Document " + testFileName + " uploaded."; - VersionLanguagesPage projectVersionPage = - new LoginWorkFlow().signIn("admin", "admin") - .goToProjects() - .goToProject("about fedora") - .gotoVersion("master") - .gotoSettingsTab() - .gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(htmlfile.getAbsolutePath()) - .submitUpload(); - assertThat("Document uploaded notification shows", - projectVersionPage.getNotificationMessage(), - Matchers.equalTo(successfullyUploaded)); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("html-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(htmlfile.getAbsolutePath()) + .submitUpload() + .clickUploadDone(); VersionDocumentsPage versionDocumentsPage = - projectVersionPage.gotoDocumentTab(); + versionDocumentsTab.gotoDocumentTab(); + + assertThat(versionDocumentsPage. + sourceDocumentsContains(htmlfile.getName())) + .as("Document shows in table"); + + EditorPage editorPage = versionDocumentsPage + .gotoLanguageTab() + .translate("pl", testFileName); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Test content") + .as("The first translation source is correct"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("This is Bold text") + .as("The second translation source is correct"); + } + + @Feature(bugzilla = 980670, + summary = "Maintainer can upload a HTML file for translation", + tcmsTestCaseIds = { 377837 }, + tcmsTestPlanIds = { 5316 } ) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void uploadHTMLFileAsMaintainer() throws Exception { + File htmlfile = testFileGenerator.generateTestFileWithContent( + "testhtmlfile", ".html", + "Test content" + + "
This is Bold text" + ); + String testFileName = htmlfile.getName(); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("translator", "translator") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("html-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(htmlfile.getAbsolutePath()) + .submitUpload() + .clickUploadDone(); - assertThat("Document shows in table", versionDocumentsPage - .sourceDocumentsContains(htmlfile.getName())); + VersionDocumentsPage versionDocumentsPage = + versionDocumentsTab.gotoDocumentTab(); - EditorPage editorPage = - projectVersionPage.goToProjects().goToProject("about fedora") - .gotoVersion("master").translate("pl", testFileName); + assertThat(versionDocumentsPage + .sourceDocumentsContains(htmlfile.getName())) + .as("Document shows in table"); - assertThat("The first translation source is correct", - editorPage.getMessageSourceAtRowIndex(0), - Matchers.equalTo("Test content")); - assertThat("The second translation source is correct", - editorPage.getMessageSourceAtRowIndex(1), - Matchers.equalTo("This is Bold text")); + EditorPage editorPage = versionDocumentsPage + .gotoLanguageTab() + .translate("pl", testFileName); + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Test content") + .as("The first translation source is correct"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("This is Bold text") + .as("The second translation source is correct"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/document/MultiFileUploadTest.java b/functional-test/src/test/java/org/zanata/feature/document/MultiFileUploadTest.java new file mode 100644 index 0000000000..d974b21a53 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/document/MultiFileUploadTest.java @@ -0,0 +1,163 @@ +/* + * Copyright 2013, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.feature.document; + +import java.io.File; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; +import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.page.projectversion.VersionDocumentsPage; +import org.zanata.page.projectversion.versionsettings.VersionDocumentsTab; +import org.zanata.util.CleanDocumentStorageRule; +import org.zanata.util.SampleProjectRule; +import org.zanata.util.TestFileGenerator; +import org.zanata.workflow.BasicWorkFlow; +import org.zanata.workflow.LoginWorkFlow; +import org.zanata.workflow.ProjectWorkFlow; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Damian Jansen + * djansen@redhat.com + */ +@Category(DetailedTest.class) +@Slf4j +public class MultiFileUploadTest extends ZanataTestCase { + + @ClassRule + public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); + + @Rule + public CleanDocumentStorageRule documentStorageRule = + new CleanDocumentStorageRule(); + + private TestFileGenerator testFileGenerator = new TestFileGenerator(); + private String documentStorageDirectory; + + + @BeforeClass + public static void beforeClass() { + new LoginWorkFlow().signIn("admin", "admin"); + new ProjectWorkFlow().createNewProjectVersion( + "about fedora", "multi-upload", "File") + .logout(); + } + + @Before + public void before() { + new BasicWorkFlow().goToHome().deleteCookiesAndRefresh(); + documentStorageDirectory = CleanDocumentStorageRule + .getDocumentStoragePath() + .concat(File.separator) + .concat("documents") + .concat(File.separator); + + if (new File(documentStorageDirectory).exists()) { + log.warn("Document storage directory exists (cleanup incomplete)"); + } + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + @Category(BasicAcceptanceTest.class) + public void uploadedDocumentsAreInFilesystem() { + File firstFile = testFileGenerator.generateTestFileWithContent( + "multiuploadInFilesystem", ".txt", + "This is a test file"); + File secondFile = testFileGenerator.generateTestFileWithContent( + "multiuploadInFilesystem2", ".txt", + "This is another test file"); + String testFileName = firstFile.getName(); + + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("multi-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(firstFile.getAbsolutePath()) + .enterFilePath(secondFile.getAbsolutePath()) + .submitUpload() + .clickUploadDone(); + + assertThat(new File(documentStorageDirectory).list().length) + .isEqualTo(2) + .as("There are two uploaded source files"); + + VersionDocumentsPage versionDocumentsPage = versionDocumentsTab + .gotoDocumentTab() + .waitForSourceDocsContains(testFileName); + + assertThat(versionDocumentsPage.getSourceDocumentNames()) + .contains(firstFile.getName()) + .contains(secondFile.getName()) + .as("The documents were uploaded"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void removeFileFromUploadList() { + File keptUploadFile = testFileGenerator.generateTestFileWithContent( + "removeFileFromUploadList", ".txt", "Remove File Upload Test"); + + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("multi-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(keptUploadFile.getAbsolutePath()) + .enterFilePath("/tmp/fakefile.txt"); + + assertThat(versionDocumentsTab.getUploadList()) + .contains(keptUploadFile.getName()) + .contains("fakefile.txt") + .as("The intended files are listed"); + + versionDocumentsTab = versionDocumentsTab.clickRemoveOn("fakefile.txt"); + + assertThat(versionDocumentsTab.getUploadList()) + .contains(keptUploadFile.getName()) + .doesNotContain("fakefile.txt") + .as("The fakefile has been removed"); + + VersionDocumentsPage versionDocumentsPage = versionDocumentsTab + .submitUpload() + .clickUploadDone() + .gotoDocumentTab(); + + assertThat(versionDocumentsPage.getSourceDocumentNames()) + .contains(keptUploadFile.getName()) + .doesNotContain("fakefile.txt") + .as("Only the intended file was uploaded"); + } +} diff --git a/functional-test/src/test/java/org/zanata/feature/document/SubtitleDocumentTypeTest.java b/functional-test/src/test/java/org/zanata/feature/document/SubtitleDocumentTypeTest.java new file mode 100644 index 0000000000..8a2434f55d --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/document/SubtitleDocumentTypeTest.java @@ -0,0 +1,274 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.feature.document; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.page.projectversion.VersionDocumentsPage; +import org.zanata.page.projectversion.VersionLanguagesPage; +import org.zanata.page.projectversion.versionsettings.VersionDocumentsTab; +import org.zanata.page.webtrans.EditorPage; +import org.zanata.util.CleanDocumentStorageRule; +import org.zanata.util.SampleProjectRule; +import org.zanata.util.TestFileGenerator; +import org.zanata.workflow.BasicWorkFlow; +import org.zanata.workflow.LoginWorkFlow; +import org.zanata.workflow.ProjectWorkFlow; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.zanata.util.FunctionalTestHelper.assumeTrue; + +/** + * Covers more detailed testing of the subtitle formats + * @see DocTypeUploadTest + * @author Damian Jansen + * djansen@redhat.com + */ +@Category(DetailedTest.class) +public class SubtitleDocumentTypeTest extends ZanataTestCase { + + @ClassRule + public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); + + @Rule + public CleanDocumentStorageRule documentStorageRule = + new CleanDocumentStorageRule(); + + private TestFileGenerator testFileGenerator = new TestFileGenerator(); + private String sep = System.getProperty("line.separator"); + + @BeforeClass + public static void beforeClass() { + new LoginWorkFlow().signIn("admin", "admin"); + new ProjectWorkFlow().createNewProjectVersion( + "about fedora", "subtitle-upload", "File") + .logout(); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void similarSrtEntriesAreIndividual() throws Exception { + EditorPage editorPage = uploadAndGoToDocument(testFileGenerator + .generateTestFileWithContent("duplicationinsrtfile", ".srt", + "1" + sep + + "00:00:01,000 --> 00:00:02,000" + sep + + "Exactly the same text" + sep + sep + + "2" + sep + + "00:00:02,000 --> 00:00:03,000" + sep + + "Exactly the same text")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Exactly the same text") + .as("The first translation source is correct"); + + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Exactly the same text") + .as("The second translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void webVttLabelsAreNotParsed() throws Exception { + EditorPage editorPage = uploadAndGoToDocument(testFileGenerator + .generateTestFileWithContent("labelledVttfile", ".vtt", + "Introduction" + sep + + "00:00:01.000 --> 00:00:02.000" + sep + + "Test subtitle 1")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Test subtitle 1") + .as("The translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void multilineSRTAreParsedCorrectly() throws Exception { + EditorPage editorPage = uploadAndGoToDocument(testFileGenerator + .generateTestFileWithContent("multilinesrtfile", ".srt", + "1" + sep + + "00:00:01,000 --> 00:00:02,000" + sep + + "Test subtitle 1" + sep + + "Test subtitle 1 line 2" + sep + sep + + "2" + sep + + "00:00:03,000 --> 00:00:04,000" + sep + + "Test subtitle 2")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Test subtitle 1" + sep + "Test subtitle 1 line 2") + .as("The first translation source is correct"); + + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Test subtitle 2") + .as("The second translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void multilineVTTAreParsedCorrectly() throws Exception { + EditorPage editorPage = uploadAndGoToDocument(testFileGenerator + .generateTestFileWithContent("multilinevttfile", ".vtt", + "00:00:01.000 --> 00:00:02.000" + sep + + "Test subtitle 1" + sep + + "Test subtitle 1 line 2" + sep + sep + + "00:00:03.000 --> 00:00:04.000" + sep + + "Test subtitle 2")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Test subtitle 1" + sep + "Test subtitle 1 line 2") + .as("The first translation source is correct"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Test subtitle 2") + .as("The second translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void multilineSBTAreParsedCorrectly() throws Exception { + EditorPage editorPage = uploadAndGoToDocument(testFileGenerator + .generateTestFileWithContent("multilinesbtfile", ".sbt", + "00:04:35.03,00:04:38.82" + sep + + "Test subtitle 1" + sep + + "Test subtitle 1 line 2" + sep + sep + + "2" + sep + + "00:04:39.03,00:04:44.82" + sep + + "Test subtitle 2")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Test subtitle 1" + sep + "Test subtitle 1 line 2") + .as("The first translation source is correct"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Test subtitle 2") + .as("The second translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void multilineSubAreParsedCorrectly() throws Exception { + EditorPage editorPage = uploadAndGoToDocument(testFileGenerator + .generateTestFileWithContent("multilinesubfile", ".sub", + "00:04:35.03,00:04:38.82" + sep + + "Test subtitle 1" + sep + + "Test subtitle 1 line 2" + sep + sep + + "00:04:39.03,00:04:44.82" + sep + + "Test subtitle 2")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Test subtitle 1" + sep + "Test subtitle 1 line 2") + .as("The first translation source is correct"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Test subtitle 2") + .as("The second translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void formattingInSrtEntries() throws Exception { + EditorPage editorPage = uploadAndGoToDocument( + testFileGenerator.generateTestFileWithContent( + "formattedsrtfile", + ".srt", + "1" + sep + "00:00:01,000 --> 00:00:02,000" + sep + + "Exactly the same text {u}and more{/u}")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Exactly the same text {u}and more{/u}") + .as("The translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void formattingInVttEntries() throws Exception { + EditorPage editorPage = uploadAndGoToDocument( + testFileGenerator.generateTestFileWithContent( + "formattedvttfile", + ".vtt", + "00:00:01.000 --> 00:00:02.000" + sep + + "Exactly the same text {u}and more{/u}")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Exactly the same text {u}and more{/u}") + .as("The translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void formattingInSbtEntries() throws Exception { + EditorPage editorPage = uploadAndGoToDocument( + testFileGenerator.generateTestFileWithContent( + "formattedsbtfile", + ".sbt", + "00:04:35.03,00:04:38.82" + sep + + "Exactly the same text {u}and more{/u}")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Exactly the same text {u}and more{/u}") + .as("The translation source is correct"); + } + + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void formattingInSubEntries() throws Exception { + EditorPage editorPage = uploadAndGoToDocument( + testFileGenerator.generateTestFileWithContent( + "formattedsubfile", + ".sub", + "00:04:35.03,00:04:38.82" + sep + + "Exactly the same text {u}and more{/u}")); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Exactly the same text {u}and more{/u}") + .as("The translation source is correct"); + } + + /* + * Upload and open the test file in the editor for verification + */ + private EditorPage uploadAndGoToDocument(File testFile) { + VersionDocumentsPage versionDocumentsPage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("subtitle-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(testFile.getAbsolutePath()) + .submitUpload() + .clickUploadDone() + .gotoDocumentTab(); + + assertThat(versionDocumentsPage.sourceDocumentsContains(testFile + .getName())).as("Document shows in table"); + + return versionDocumentsPage + .gotoLanguageTab() + .translate("pl", testFile.getName()); + } + + private boolean storageIsClean(String documentStorageDirectory) { + File testDir; + try { + testDir = new File(documentStorageDirectory); + return testDir.listFiles().equals(null) || + testDir.listFiles().length == 0; + } catch (NullPointerException npe) { + return true; + } + } +} diff --git a/functional-test/src/test/java/org/zanata/feature/document/UploadTest.java b/functional-test/src/test/java/org/zanata/feature/document/UploadTest.java index 12abbba142..cae51a2683 100644 --- a/functional-test/src/test/java/org/zanata/feature/document/UploadTest.java +++ b/functional-test/src/test/java/org/zanata/feature/document/UploadTest.java @@ -23,8 +23,9 @@ import java.io.File; import lombok.extern.slf4j.Slf4j; -import org.hamcrest.Matchers; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -33,27 +34,27 @@ import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projectversion.VersionDocumentsPage; -import org.zanata.page.projectversion.VersionLanguagesPage; import org.zanata.page.projectversion.versionsettings.VersionDocumentsTab; import org.zanata.util.CleanDocumentStorageRule; import org.zanata.util.SampleProjectRule; import org.zanata.util.TestFileGenerator; import org.zanata.workflow.BasicWorkFlow; import org.zanata.workflow.LoginWorkFlow; +import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.FunctionalTestHelper.assumeTrue; /** - * @author Damian Jansen djansen@redhat.com + * @author Damian Jansen + * djansen@redhat.com */ @Category(DetailedTest.class) @Slf4j public class UploadTest extends ZanataTestCase { - @Rule - public SampleProjectRule sampleProjectRule = new SampleProjectRule(); + @ClassRule + public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); @Rule public CleanDocumentStorageRule documentStorageRule = @@ -62,6 +63,15 @@ public class UploadTest extends ZanataTestCase { private TestFileGenerator testFileGenerator = new TestFileGenerator(); private String documentStorageDirectory; + + @BeforeClass + public static void beforeClass() { + new LoginWorkFlow().signIn("admin", "admin"); + new ProjectWorkFlow().createNewProjectVersion( + "about fedora", "txt-upload", "File") + .logout(); + } + @Before public void before() { new BasicWorkFlow().goToHome().deleteCookiesAndRefresh(); @@ -76,7 +86,7 @@ public void before() { } } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) @Category(BasicAcceptanceTest.class) public void uploadedDocumentIsInFilesystem() { File originalFile = @@ -85,34 +95,39 @@ public void uploadedDocumentIsInFilesystem() { "This is a test file"); String testFileName = originalFile.getName(); - VersionLanguagesPage projectVersionPage = - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(originalFile.getAbsolutePath()) - .submitUpload(); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("txt-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(originalFile.getAbsolutePath()) + .submitUpload() + .clickUploadDone(); - // We should be able to assume the new file is the only file - assertThat("There is only one uploaded source file", new File( - documentStorageDirectory).list().length, Matchers.equalTo(1)); + assertThat(new File(documentStorageDirectory).list().length) + .isEqualTo(1) + .as("There is only one uploaded source file"); File newlyCreatedFile = new File(documentStorageDirectory, testFileGenerator .getFirstFileNameInDirectory(documentStorageDirectory)); - assertThat("The contents of the file were also uploaded", - testFileGenerator.getTestFileContent(newlyCreatedFile), - Matchers.equalTo("This is a test file")); - VersionDocumentsPage versionDocumentsPage = projectVersionPage + assertThat(testFileGenerator.getTestFileContent(newlyCreatedFile)) + .isEqualTo("This is a test file") + .as("The contents of the file were also uploaded"); + VersionDocumentsPage versionDocumentsPage = versionDocumentsTab .gotoDocumentTab() .waitForSourceDocsContains(testFileName); - assertThat("Document shows in table", - versionDocumentsPage.sourceDocumentsContains(testFileName)); + assertThat(versionDocumentsPage.sourceDocumentsContains(testFileName)) + .isTrue() + .as("Document shows in table"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void cancelFileUpload() { File cancelUploadFile = testFileGenerator.generateTestFileWithContent( @@ -122,51 +137,59 @@ public void cancelFileUpload() { .signIn("admin", "admin") .goToProjects() .goToProject("about fedora") - .gotoVersion("master") + .gotoVersion("txt-upload") .gotoSettingsTab() .gotoSettingsDocumentsTab() .pressUploadFileButton() .enterFilePath(cancelUploadFile.getAbsolutePath()) .cancelUpload(); - assertThat("Document does not show in table", - !versionDocumentsTab - .sourceDocumentsContains("cancelFileUpload.txt")); + assertThat(versionDocumentsTab.sourceDocumentsContains("cancelFileUpload.txt")) + .isFalse() + .as("Document does not show in table"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void emptyFilenameUpload() { - VersionDocumentsTab versionDocumentsTab = - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsDocumentsTab() - .pressUploadFileButton(); - - assertThat("The upload button is not available", - !versionDocumentsTab.canSubmitDocument()); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("txt-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton(); + + assertThat(versionDocumentsTab.canSubmitDocument()) + .isFalse() + .as("The upload button is not available"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) @Ignore("RHBZ-990836") public void handleReallyBigFile() { File bigFile = - testFileGenerator.generateTestFileWithContent("bigFile", - ".txt", "Big file content"); + testFileGenerator.generateTestFileWithContent( + "bigFile", ".txt", "Big file content"); long fileSizeInMB = (1024 * 1024) * 500; testFileGenerator.forceFileSize(bigFile, fileSizeInMB); assumeTrue("Data file " + bigFile.getName() + " is big", bigFile.length() == fileSizeInMB); - VersionLanguagesPage projectVersionPage = - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(bigFile.getAbsolutePath()) - .submitUpload(); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("txt-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(bigFile.getAbsolutePath()) + .submitUpload() + .clickUploadDone(); - projectVersionPage.assertNoCriticalErrors(); + versionDocumentsTab.assertNoCriticalErrors(); // TODO: Verify graceful handling of scenario } @@ -179,99 +202,102 @@ public void failOnInvalidFileUpload() { String successfullyUploaded = "Document " + noFile.getName() + " uploaded."; - VersionDocumentsTab versionDocumentsTab = - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(noFile.getAbsolutePath()); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("txt-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(noFile.getAbsolutePath()); - assertThat("Data file " + noFile.getName() + " does not exist", - noFile.delete() && !noFile.exists()); + assertThat(noFile.delete() && !noFile.exists()) + .as("Data file " + noFile.getName() + " does not exist"); - VersionLanguagesPage versionLanguagesPage = versionDocumentsTab - .submitUpload(); - versionLanguagesPage.assertNoCriticalErrors(); - assertThat("Success message is shown", - versionLanguagesPage.expectNotification(successfullyUploaded)); + versionDocumentsTab = versionDocumentsTab + .submitUpload() + .clickUploadDone(); + + versionDocumentsTab.assertNoCriticalErrors(); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void handleVeryLongFileNames() { - File longFile = - testFileGenerator.generateTestFileWithContent( - testFileGenerator.longFileName(), ".txt", - "This filename is long"); - String successfullyUploaded = - "Document " + longFile.getName() + " uploaded."; - - VersionLanguagesPage projectVersionPage = - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(longFile.getAbsolutePath()) - .submitUpload(); - - assertThat("Document uploaded notification shows", - projectVersionPage.expectNotification(successfullyUploaded)); + File longFile = testFileGenerator.generateTestFileWithContent( + testFileGenerator.longFileName(), ".txt", + "This filename is long"); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("txt-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(longFile.getAbsolutePath()) + .submitUpload() + .clickUploadDone(); - VersionDocumentsPage versionDocumentsPage = projectVersionPage + VersionDocumentsPage versionDocumentsPage = versionDocumentsTab .gotoDocumentTab() .waitForSourceDocsContains(longFile.getName()); - assertThat("Document shows in table", versionDocumentsPage - .sourceDocumentsContains(longFile.getName())); + assertThat(versionDocumentsPage.sourceDocumentsContains(longFile.getName())) + .isTrue() + .as("Document shows in table"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void emptyFile() { - File emptyFile = - testFileGenerator.generateTestFileWithContent("emptyFile", - ".txt", ""); - String successfullyUploaded = - "Document " + emptyFile.getName() + " uploaded."; - + File emptyFile = testFileGenerator + .generateTestFileWithContent("emptyFile", ".txt", ""); assumeTrue("File is empty", emptyFile.length() == 0); - VersionLanguagesPage projectVersionPage = - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(emptyFile.getAbsolutePath()) - .submitUpload(); + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("txt-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(emptyFile.getAbsolutePath()) + .submitUpload() + .clickUploadDone(); - assertThat("Data file emptyFile.txt still exists", emptyFile.exists()); - assertThat("Document uploaded notification shows", - projectVersionPage.expectNotification(successfullyUploaded)); + assertThat(emptyFile.exists()) + .isTrue() + .as("Data file emptyFile.txt still exists"); - VersionDocumentsPage versionDocumentsPage = projectVersionPage + VersionDocumentsPage versionDocumentsPage = versionDocumentsTab .gotoDocumentTab() .waitForSourceDocsContains(emptyFile.getName()); - assertThat("Document shows in table", versionDocumentsPage - .sourceDocumentsContains(emptyFile.getName())); + assertThat(versionDocumentsPage.sourceDocumentsContains(emptyFile.getName())) + .isTrue() + .as("Document shows in table"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void rejectUnsupportedValidFiletype() { - File unsupportedFile = - testFileGenerator.generateTestFileWithContent("testfodt", - ".fodt", ""); - String uploadFailed = - "Unrecognized file extension for " + unsupportedFile.getName(); - - VersionLanguagesPage projectVersionPage = - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(unsupportedFile.getAbsolutePath()) - .submitUpload(); - - assertThat("Unrecognized file extension error is shown", - projectVersionPage.expectNotification(uploadFailed)); + File unsupportedFile = testFileGenerator + .generateTestFileWithContent("testfodt", ".fodt", ""); + + VersionDocumentsTab versionDocumentsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoVersion("txt-upload") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(unsupportedFile.getAbsolutePath()) + .submitUpload(); + + assertThat(versionDocumentsTab.getUploadError()) + .contains("is not valid for a source file on this server") + .as("Unrecognized file extension error is shown"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/editor/EditorFilterMessagesTest.java b/functional-test/src/test/java/org/zanata/feature/editor/EditorFilterMessagesTest.java index 97e3655a56..3ee96d9422 100644 --- a/functional-test/src/test/java/org/zanata/feature/editor/EditorFilterMessagesTest.java +++ b/functional-test/src/test/java/org/zanata/feature/editor/EditorFilterMessagesTest.java @@ -12,6 +12,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; @@ -44,11 +45,14 @@ public void setUp() { new LoginWorkFlow().signIn("admin", "admin"); } - @Test + @Feature(summary = "The user can filter translation entries using more " + + "than one search term", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void canFilterByMultipleFields() { EditorPage editorPage = new BasicWorkFlow().goToEditor("about-fedora", "master", "fr", - document).setSyntaxHighlighting(false); + document); assertThat(editorPage.getMessageSources()).containsExactly( "hello world", "greetings", "hey"); final EditorPage page = editorPage.inputFilterQuery("resource-id:res2"); @@ -61,7 +65,9 @@ public List call() throws Exception { }, Matchers.contains("greetings")); } - @Test + @Feature(summary = "The user may save the filter url for later use", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void editorFilterIsBookmarkable() { String urlForEditor = String.format(BasicWorkFlow.EDITOR_TEMPLATE, "about-fedora", @@ -70,7 +76,7 @@ public void editorFilterIsBookmarkable() { urlForEditor + ";search:hello%20w;resid:res1"; EditorPage editorPage = new BasicWorkFlow().goToPage(urlWithFilterCondition, - EditorPage.class).setSyntaxHighlighting(false); + EditorPage.class); assertThat(editorPage.getMessageSources()).containsExactly("hello world"); assertThat(editorPage.getFilterQuery().trim()).isEqualTo("text:hello w resource-id:res1"); diff --git a/functional-test/src/test/java/org/zanata/feature/editor/TranslateHTMLTest.java b/functional-test/src/test/java/org/zanata/feature/editor/TranslateHTMLTest.java index 7c559083f6..16ecd92e08 100644 --- a/functional-test/src/test/java/org/zanata/feature/editor/TranslateHTMLTest.java +++ b/functional-test/src/test/java/org/zanata/feature/editor/TranslateHTMLTest.java @@ -23,14 +23,15 @@ import java.io.File; import java.util.HashMap; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.experimental.categories.Category; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; +import org.junit.rules.Timeout; import org.junit.runner.RunWith; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; @@ -41,7 +42,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.FunctionalTestHelper.assumeFalse; /** @@ -52,6 +53,9 @@ @Category(DetailedTest.class) public class TranslateHTMLTest extends ZanataTestCase { + @Rule + public Timeout timeout = new Timeout(ZanataTestCase.MAX_LONG_TEST_DURATION); + @Rule public SampleProjectRule sampleProjectRule = new SampleProjectRule(); @@ -77,71 +81,63 @@ public void before() { new LoginWorkFlow().signIn("admin", "admin"); } + @Feature(summary = "The user can translate HyperText Markup Language files", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) @Theory public void translateBasicHTMLFile(String extension) { - File testfile = - testFileGenerator.generateTestFileWithContent("basichtml", "." - + extension, "Line One

Line Two

" - + "Line Three"); - - HashMap projectSettings = - ProjectWorkFlow.projectDefaults(); - projectSettings.put("Project ID", extension + "-project"); - projectSettings.put("Name", extension + "-project"); - projectSettings.put("Project Type", "File"); + File testfile = testFileGenerator.generateTestFileWithContent( + "basichtml", "." + extension, + "Line One

Line Two

Line Three"); EditorPage editorPage = new ProjectWorkFlow() - .createNewProject(projectSettings) - .clickCreateVersionLink().inputVersionId(extension) - .saveVersion() + .goToProjectByName("about fedora") + .gotoVersion("master") .gotoSettingsTab() .gotoSettingsDocumentsTab() .pressUploadFileButton() .enterFilePath(testfile.getAbsolutePath()) .submitUpload() + .clickUploadDone() + .gotoLanguageTab() .translate("fr", testfile.getName()); - assertThat("Item 1 shows Line One", - editorPage.getMessageSourceAtRowIndex(0), - Matchers.equalTo("Line One")); - assertThat("Item 2 shows Line Two", - editorPage.getMessageSourceAtRowIndex(1), - Matchers.equalTo("Line Two")); - assertThat("Item 3 shows Line Three", - editorPage.getMessageSourceAtRowIndex(2), - Matchers.equalTo("Line Three")); - - editorPage = - editorPage.translateTargetAtRowIndex(0, "Une Ligne") - .approveTranslationAtRow(0); - editorPage = - editorPage.translateTargetAtRowIndex(1, "Deux Ligne") - .approveTranslationAtRow(1); - editorPage = - editorPage.translateTargetAtRowIndex(2, "Ligne Trois") - .approveTranslationAtRow(2); - - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); - - // Close and reopen the editor to test save, switches to CodeMirror + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Line One") + .as("Item 1 shows Line One"); + + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Line Two") + .as("Item 2 shows Line Two"); + assertThat(editorPage.getMessageSourceAtRowIndex(2)) + .isEqualTo("Line Three") + .as("Item 3 shows Line Three"); + + editorPage = editorPage + .translateTargetAtRowIndex(0, "Une Ligne") + .approveTranslationAtRow(0) + .translateTargetAtRowIndex(1, "Deux Ligne") + .approveTranslationAtRow(1) + .translateTargetAtRowIndex(2, "Ligne Trois") + .approveTranslationAtRow(2); + + assertTranslations(editorPage); + + // Close and reopen the editor to test save editorPage.reload(); - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); + assertTranslations(editorPage); + + } + + private void assertTranslations(EditorPage editorPage) { + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0)) + .isEqualTo("Une Ligne") + .as("Item 1 shows a translation of Line One"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(1)) + .isEqualTo("Deux Ligne") + .as("Item 2 shows a translation of Line Two"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(2)) + .isEqualTo("Ligne Trois") + .as("Item 3 shows a translation of Line Three"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/editor/TranslateIdmlTest.java b/functional-test/src/test/java/org/zanata/feature/editor/TranslateIdmlTest.java index d57b46fcc7..2660ff7909 100644 --- a/functional-test/src/test/java/org/zanata/feature/editor/TranslateIdmlTest.java +++ b/functional-test/src/test/java/org/zanata/feature/editor/TranslateIdmlTest.java @@ -23,14 +23,13 @@ import java.io.File; import java.util.HashMap; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; -import org.zanata.page.projectversion.VersionLanguagesPage; import org.zanata.page.webtrans.EditorPage; import org.zanata.util.CleanDocumentStorageRule; import org.zanata.util.SampleProjectRule; @@ -39,7 +38,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.FunctionalTestHelper.assumeFalse; /** @@ -69,71 +68,58 @@ public void before() { new LoginWorkFlow().signIn("admin", "admin"); } - @Test + @Feature(summary = "The user can translate an InDesign file", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void translateBasicIdmlFile() { File testfile = testFileGenerator.openTestFile("test-idml.idml"); - HashMap projectSettings = - ProjectWorkFlow.projectDefaults(); - projectSettings.put("Project ID", "idml-project"); - projectSettings.put("Name", "idml-project"); - projectSettings.put("Project Type", "File"); - - VersionLanguagesPage projectVersionPage = - new ProjectWorkFlow().createNewProject(projectSettings) - .clickCreateVersionLink().inputVersionId("idml") - .saveVersion() - .gotoSettingsTab() - .gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(testfile.getAbsolutePath()) - .submitUpload(); - - EditorPage editorPage = - projectVersionPage.translate("fr", - testfile.getName()); - - assertThat("Item 1 shows Line One", - editorPage.getMessageSourceAtRowIndex(0), - Matchers.equalTo("Line One")); - assertThat("Item 2 shows Line Two", - editorPage.getMessageSourceAtRowIndex(1), - Matchers.equalTo("Line Two")); - assertThat("Item 3 shows Line Three", - editorPage.getMessageSourceAtRowIndex(2), - Matchers.equalTo("Line Three")); - - editorPage = - editorPage.translateTargetAtRowIndex(0, "Une Ligne") - .approveTranslationAtRow(0); - editorPage = - editorPage.translateTargetAtRowIndex(1, "Deux Ligne") - .approveTranslationAtRow(1); - editorPage = - editorPage.translateTargetAtRowIndex(2, "Ligne Trois") - .approveTranslationAtRow(2); - - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); - - // Close and reopen the editor to test save, switches to CodeMirror + EditorPage editorPage = new ProjectWorkFlow() + .goToProjectByName("about fedora") + .gotoVersion("master") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(testfile.getAbsolutePath()) + .submitUpload() + .clickUploadDone() + .gotoLanguageTab() + .translate("fr", testfile.getName()); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Line One") + .as("Item 1 shows Line One"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Line Two") + .as("Item 2 shows Line Two"); + assertThat(editorPage.getMessageSourceAtRowIndex(2)) + .isEqualTo("Line Three") + .as("Item 3 shows Line Three"); + + editorPage = editorPage.translateTargetAtRowIndex(0, "Une Ligne") + .approveTranslationAtRow(0) + .translateTargetAtRowIndex(1, "Deux Ligne") + .approveTranslationAtRow(1) + .translateTargetAtRowIndex(2, "Ligne Trois") + .approveTranslationAtRow(2); + + assertTranslations(editorPage); + + // Close and reopen the editor to test save editorPage.reload(); - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); + assertTranslations(editorPage); + } + + private void assertTranslations(EditorPage editorPage) { + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0)) + .isEqualTo("Une Ligne") + .as("Item 1 shows a translation of Line One"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(1)) + .isEqualTo("Deux Ligne") + .as("Item 2 shows a translation of Line Two"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(2)) + .isEqualTo("Ligne Trois") + .as("Item 3 shows a translation of Line Three"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/editor/TranslateOdsTest.java b/functional-test/src/test/java/org/zanata/feature/editor/TranslateOdsTest.java index fb59555c88..b66a89277b 100644 --- a/functional-test/src/test/java/org/zanata/feature/editor/TranslateOdsTest.java +++ b/functional-test/src/test/java/org/zanata/feature/editor/TranslateOdsTest.java @@ -23,11 +23,11 @@ import java.io.File; import java.util.HashMap; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projectversion.VersionLanguagesPage; @@ -39,7 +39,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.FunctionalTestHelper.assumeFalse; /** @@ -69,94 +69,75 @@ public void before() { new LoginWorkFlow().signIn("admin", "admin"); } - @Test + @Feature(summary = "The user can translate an OpenOffice spreadsheet file", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void translateBasicOdsFile() { File testfile = testFileGenerator.openTestFile("test-ods.ods"); - HashMap projectSettings = - ProjectWorkFlow.projectDefaults(); - projectSettings.put("Project ID", "ods-project"); - projectSettings.put("Name", "ods-project"); - projectSettings.put("Project Type", "File"); - - VersionLanguagesPage projectVersionPage = - new ProjectWorkFlow().createNewProject(projectSettings) - .clickCreateVersionLink().inputVersionId("ods") - .saveVersion() - .gotoSettingsTab() - .gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(testfile.getAbsolutePath()) - .submitUpload(); - - EditorPage editorPage = - projectVersionPage.translate("fr", testfile.getName()); - - assertThat("Item 1 shows TestODS (the sheet name)", - editorPage.getMessageSourceAtRowIndex(0), - Matchers.equalTo("TestODS")); - assertThat("Item 2 shows First (the page name)", - editorPage.getMessageSourceAtRowIndex(1), - Matchers.equalTo("First")); - assertThat("Item 3 shows Line One", - editorPage.getMessageSourceAtRowIndex(2), - Matchers.equalTo("Line One")); - assertThat("Item 4 shows Line Two", - editorPage.getMessageSourceAtRowIndex(3), - Matchers.equalTo("Line Two")); - assertThat("Item 5 shows Line Three", - editorPage.getMessageSourceAtRowIndex(4), - Matchers.equalTo("Line Three")); - - editorPage = - editorPage.translateTargetAtRowIndex(0, "TestODS") - .approveTranslationAtRow(0); - editorPage = - editorPage.translateTargetAtRowIndex(1, "Début") - .approveTranslationAtRow(1); - editorPage = - editorPage.translateTargetAtRowIndex(2, "Une Ligne") - .approveTranslationAtRow(2); - editorPage = - editorPage.translateTargetAtRowIndex(3, "Deux Ligne") - .approveTranslationAtRow(3); - editorPage = - editorPage.translateTargetAtRowIndex(4, "Ligne Trois") - .approveTranslationAtRow(4); - - assertThat("Item 1 shows a translation of the sheet name", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("TestODS")); - assertThat("Item 2 shows a translation of page name", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Début")); - assertThat("Item 3 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Une Ligne")); - assertThat("Item 4 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(3), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 5 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(4), - Matchers.equalTo("Ligne Trois")); + EditorPage editorPage = new ProjectWorkFlow() + .goToProjectByName("about fedora") + .gotoVersion("master") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(testfile.getAbsolutePath()) + .submitUpload() + .clickUploadDone() + .gotoLanguageTab() + .translate("fr", testfile.getName()); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("TestODS") + .as("Item 1 shows TestODS (the sheet name)"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("First") + .as("Item 2 shows First (the page name)"); + assertThat(editorPage.getMessageSourceAtRowIndex(2)) + .isEqualTo("Line One") + .as("Item 3 shows Line One"); + assertThat(editorPage.getMessageSourceAtRowIndex(3)) + .isEqualTo("Line Two") + .as("Item 4 shows Line Two"); + assertThat(editorPage.getMessageSourceAtRowIndex(4)) + .isEqualTo("Line Three") + .as("Item 5 shows Line Three"); + + editorPage = editorPage + .translateTargetAtRowIndex(0, "TestODS") + .approveTranslationAtRow(0) + .translateTargetAtRowIndex(1, "Début") + .approveTranslationAtRow(1) + .translateTargetAtRowIndex(2, "Une Ligne") + .approveTranslationAtRow(2) + .translateTargetAtRowIndex(3, "Deux Ligne") + .approveTranslationAtRow(3) + .translateTargetAtRowIndex(4, "Ligne Trois") + .approveTranslationAtRow(4); + + assertTranslations(editorPage); // Close and reopen the editor to test save, switches to CodeMirror editorPage.reload(); - assertThat("Item 1 shows a translation of the sheet name", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("TestODS")); - assertThat("Item 2 shows a translation of page name", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Début")); - assertThat("Item 3 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Une Ligne")); - assertThat("Item 4 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(3), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 5 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(4), - Matchers.equalTo("Ligne Trois")); + assertTranslations(editorPage); + } + + private void assertTranslations(EditorPage editorPage) { + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0)) + .isEqualTo("TestODS") + .as("Item 1 shows a translation of the sheet name"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(1)) + .isEqualTo("Début") + .as("Item 2 shows a translation of page name"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(2)) + .isEqualTo("Une Ligne") + .as("Item 3 shows a translation of Line One"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(3)) + .isEqualTo("Deux Ligne") + .as("Item 4 shows a translation of Line Two"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(4)) + .isEqualTo("Ligne Trois") + .as("Item 5 shows a translation of Line Three"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/editor/TranslateOpenOfficeTest.java b/functional-test/src/test/java/org/zanata/feature/editor/TranslateOpenOfficeTest.java index a20062053b..e9f2b64a96 100644 --- a/functional-test/src/test/java/org/zanata/feature/editor/TranslateOpenOfficeTest.java +++ b/functional-test/src/test/java/org/zanata/feature/editor/TranslateOpenOfficeTest.java @@ -23,14 +23,15 @@ import java.io.File; import java.util.HashMap; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.experimental.categories.Category; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; +import org.junit.rules.Timeout; import org.junit.runner.RunWith; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; @@ -41,7 +42,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.FunctionalTestHelper.assumeFalse; /** @@ -52,6 +53,9 @@ @Category(DetailedTest.class) public class TranslateOpenOfficeTest extends ZanataTestCase { + @Rule + public Timeout timeout = new Timeout(ZanataTestCase.MAX_LONG_TEST_DURATION); + @Rule public SampleProjectRule sampleProjectRule = new SampleProjectRule(); @@ -79,68 +83,60 @@ public void before() { new LoginWorkFlow().signIn("admin", "admin"); } + @Feature(summary = "The user can translate OpenOffice files", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) @Theory public void translateBasicOpenOfficeFile(String extension) { - File testfile = - testFileGenerator.openTestFile("test-" + extension + "." - + extension); - - HashMap projectSettings = - ProjectWorkFlow.projectDefaults(); - projectSettings.put("Project ID", extension + "-project"); - projectSettings.put("Name", extension + "-project"); - projectSettings.put("Project Type", "File"); - - EditorPage editorPage = - new ProjectWorkFlow().createNewProject(projectSettings) - .clickCreateVersionLink().inputVersionId(extension) - .saveVersion().gotoSettingsTab() - .gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(testfile.getAbsolutePath()) - .submitUpload().translate("fr", testfile.getName()); - - assertThat("Item 1 shows Line One", - editorPage.getMessageSourceAtRowIndex(0), - Matchers.equalTo("Line One")); - assertThat("Item 2 shows Line Two", - editorPage.getMessageSourceAtRowIndex(1), - Matchers.equalTo("Line Two")); - assertThat("Item 3 shows Line Three", - editorPage.getMessageSourceAtRowIndex(2), - Matchers.equalTo("Line Three")); - - editorPage = - editorPage.translateTargetAtRowIndex(0, "Une Ligne") - .approveTranslationAtRow(0); - editorPage = - editorPage.translateTargetAtRowIndex(1, "Deux Ligne") - .approveTranslationAtRow(1); - editorPage = - editorPage.translateTargetAtRowIndex(2, "Ligne Trois") - .approveTranslationAtRow(2); - - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); + File testfile = testFileGenerator + .openTestFile("test-" + extension + "." + extension); + + EditorPage editorPage = new ProjectWorkFlow() + .goToProjectByName("about fedora") + .gotoVersion("master") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(testfile.getAbsolutePath()) + .submitUpload() + .clickUploadDone() + .gotoLanguageTab() + .translate("fr", testfile.getName()); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Line One") + .as("Item 1 shows Line One"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Line Two") + .as("Item 2 shows Line Two"); + assertThat(editorPage.getMessageSourceAtRowIndex(2)) + .isEqualTo("Line Three") + .as("Item 3 shows Line Three"); + + editorPage = editorPage + .translateTargetAtRowIndex(0, "Une Ligne") + .approveTranslationAtRow(0) + .translateTargetAtRowIndex(1, "Deux Ligne") + .approveTranslationAtRow(1) + .translateTargetAtRowIndex(2, "Ligne Trois") + .approveTranslationAtRow(2); + + assertTranslations(editorPage); // Close and reopen the editor to test save, switches to CodeMirror editorPage.reload(); - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); + assertTranslations(editorPage); + } + + private void assertTranslations(EditorPage editorPage) { + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0)) + .isEqualTo("Une Ligne") + .as("Item 1 shows a translation of Line One"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(1)) + .isEqualTo("Deux Ligne") + .as("Item 2 shows a translation of Line Two"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(2)) + .isEqualTo("Ligne Trois") + .as("Item 3 shows a translation of Line Three"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/editor/TranslateTextTest.java b/functional-test/src/test/java/org/zanata/feature/editor/TranslateTextTest.java index 8390fd225e..b1a9fbb16b 100644 --- a/functional-test/src/test/java/org/zanata/feature/editor/TranslateTextTest.java +++ b/functional-test/src/test/java/org/zanata/feature/editor/TranslateTextTest.java @@ -23,11 +23,11 @@ import java.io.File; import java.util.HashMap; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; @@ -38,7 +38,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.util.FunctionalTestHelper.assumeFalse; /** @@ -68,69 +68,60 @@ public void before() { new LoginWorkFlow().signIn("admin", "admin"); } - @Test + @Feature(summary = "The user can translate a plain text file", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void translateBasicTextFile() { - File testfile = - testFileGenerator.generateTestFileWithContent("basictext", - ".txt", "Line One\nLine Two\nLine Three"); - - HashMap projectSettings = - ProjectWorkFlow.projectDefaults(); - projectSettings.put("Project ID", "text-project"); - projectSettings.put("Name", "text-project"); - projectSettings.put("Project Type", "File"); - - EditorPage editorPage = - new ProjectWorkFlow().createNewProject(projectSettings) - .clickCreateVersionLink().inputVersionId("text") - .saveVersion() - .gotoSettingsTab() - .gotoSettingsDocumentsTab() - .pressUploadFileButton() - .enterFilePath(testfile.getAbsolutePath()) - .submitUpload().translate("fr", testfile.getName()); - - assertThat("Item 1 shows Line One", - editorPage.getMessageSourceAtRowIndex(0), - Matchers.equalTo("Line One")); - assertThat("Item 2 shows Line Two", - editorPage.getMessageSourceAtRowIndex(1), - Matchers.equalTo("Line Two")); - assertThat("Item 3 shows Line Three", - editorPage.getMessageSourceAtRowIndex(2), - Matchers.equalTo("Line Three")); - - editorPage = - editorPage.translateTargetAtRowIndex(0, "Une Ligne") - .approveTranslationAtRow(0); - editorPage = - editorPage.translateTargetAtRowIndex(1, "Deux Ligne") - .approveTranslationAtRow(1); - editorPage = - editorPage.translateTargetAtRowIndex(2, "Ligne Trois") - .approveTranslationAtRow(2); - - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); + File testfile = testFileGenerator.generateTestFileWithContent( + "basictext",".txt", + "Line One\nLine Two\nLine Three"); + + EditorPage editorPage = new ProjectWorkFlow() + .goToProjectByName("about fedora") + .gotoVersion("master") + .gotoSettingsTab() + .gotoSettingsDocumentsTab() + .pressUploadFileButton() + .enterFilePath(testfile.getAbsolutePath()) + .submitUpload() + .clickUploadDone() + .gotoLanguageTab() + .translate("fr", testfile.getName()); + + assertThat(editorPage.getMessageSourceAtRowIndex(0)) + .isEqualTo("Line One") + .as("Item 1 shows Line One"); + assertThat(editorPage.getMessageSourceAtRowIndex(1)) + .isEqualTo("Line Two") + .as("Item 2 shows Line Two"); + assertThat(editorPage.getMessageSourceAtRowIndex(2)) + .isEqualTo("Line Three") + .as("Item 3 shows Line Three"); + + editorPage = editorPage.translateTargetAtRowIndex(0, "Une Ligne") + .approveTranslationAtRow(0) + .translateTargetAtRowIndex(1, "Deux Ligne") + .approveTranslationAtRow(1) + .translateTargetAtRowIndex(2, "Ligne Trois") + .approveTranslationAtRow(2); + + assertTranslations(editorPage); // Close and reopen the editor to test save, switches to CodeMirror editorPage.reload(); - assertThat("Item 1 shows a translation of Line One", - editorPage.getBasicTranslationTargetAtRowIndex(0), - Matchers.equalTo("Une Ligne")); - assertThat("Item 2 shows a translation of Line Two", - editorPage.getBasicTranslationTargetAtRowIndex(1), - Matchers.equalTo("Deux Ligne")); - assertThat("Item 3 shows a translation of Line Three", - editorPage.getBasicTranslationTargetAtRowIndex(2), - Matchers.equalTo("Ligne Trois")); + assertTranslations(editorPage); + } + + private void assertTranslations(EditorPage editorPage) { + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0)) + .isEqualTo("Une Ligne") + .as("Item 1 shows a translation of Line One"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(1)) + .isEqualTo("Deux Ligne") + .as("Item 2 shows a translation of Line Two"); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(2)) + .isEqualTo("Ligne Trois") + .as("Item 3 shows a translation of Line Three"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryAdminTest.java b/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryAdminTest.java index c992e4b17d..3139217c90 100644 --- a/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryAdminTest.java +++ b/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryAdminTest.java @@ -63,7 +63,7 @@ public class GlossaryAdminTest extends ZanataTestCase { * Setup. * @see TCMS Test Case 181711 */ - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void testGlossaryView() { // Push a glossary File projectRootPath = diff --git a/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryDeleteTest.java b/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryDeleteTest.java index 08b6bda96b..9cad9f3288 100644 --- a/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryDeleteTest.java +++ b/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryDeleteTest.java @@ -30,6 +30,7 @@ import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.webtrans.EditorPage; import org.zanata.util.SampleProjectRule; +import org.zanata.workflow.BasicWorkFlow; import org.zanata.workflow.ClientWorkFlow; import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; @@ -72,7 +73,7 @@ public void before() { basicUserConfigPath = ClientWorkFlow.getUserConfigPath("translator"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void testGlossaryDelete() throws Exception { List result = clientWorkFlow .callWithTimeout( projectRootPath, pushCommand + userConfigPath); @@ -87,21 +88,17 @@ public void testGlossaryDelete() throws Exception { .as("Glossary delete was successful"); - EditorPage editorPage = new LoginWorkFlow() - .signIn("admin", "admin") - .goToProjects() - .goToProject("about fedora") - .gotoVersion("master") - .translate("hi", "About_Fedora") - .searchGlossary("hello"); + new LoginWorkFlow().signIn("admin", "admin"); + EditorPage editorPage = + new BasicWorkFlow().goToEditor("about-fedora", "master", "hi", + "About_Fedora") + .searchGlossary("hello"); assertThat(editorPage.getGlossaryResultTable()) .as("Glossary table is empty").isEmpty(); - editorPage = new ProjectWorkFlow() - .goToProjectByName("about fedora") - .gotoVersion("master") - .translate("pl", "About_Fedora") + editorPage = new BasicWorkFlow().goToEditor("about-fedora", "master", + "pl", "About_Fedora") .searchGlossary("hello"); assertThat(editorPage.getGlossaryResultTable() @@ -109,7 +106,7 @@ public void testGlossaryDelete() throws Exception { .as("The glossary result in row 2, column 2 is correct"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void unauthorizedGlossaryDeleteRejected() throws Exception { List result = clientWorkFlow .callWithTimeout( projectRootPath, pushCommand + userConfigPath); diff --git a/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryPushTest.java b/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryPushTest.java index a339d8bd6f..41e90f2fdb 100644 --- a/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryPushTest.java +++ b/functional-test/src/test/java/org/zanata/feature/glossary/GlossaryPushTest.java @@ -74,7 +74,7 @@ public void before() { basicUserConfigPath = ClientWorkFlow.getUserConfigPath("translator"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void successfulGlossaryPush() throws Exception { List result = push(pushCommand, userConfigPath); log.info(resultByLines(result)); @@ -83,14 +83,8 @@ public void successfulGlossaryPush() throws Exception { .isTrue() .as("The glossary push was successful"); - assertThat(new LoginWorkFlow() - .signIn("translator", "translator") - .loggedInAs()) - .isEqualTo("translator") - .as("Admin has logged in"); - - EditorPage editorPage = new BasicWorkFlow() - .goToHome() + EditorPage editorPage = new LoginWorkFlow() + .signIn("admin", "admin") .goToProjects() .goToProject("about fedora") .gotoVersion("master") @@ -103,7 +97,7 @@ public void successfulGlossaryPush() throws Exception { .as("The first glossary result is correct"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void failedCSVGlossaryPush() throws Exception { List result = push(pushCSVCommand, userConfigPath); log.info(resultByLines(result)); @@ -123,7 +117,7 @@ private String resultByLines(List output) { return Joiner.on("\n").join(output); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void unauthorizedGlossaryPushRejected() throws Exception { List result = clientWorkFlow .callWithTimeout( projectRootPath, pushCommand + userConfigPath); diff --git a/functional-test/src/test/java/org/zanata/feature/glossary/InvalidGlossaryPushTest.java b/functional-test/src/test/java/org/zanata/feature/glossary/InvalidGlossaryPushTest.java index 0845dedd7e..69cd2354f9 100644 --- a/functional-test/src/test/java/org/zanata/feature/glossary/InvalidGlossaryPushTest.java +++ b/functional-test/src/test/java/org/zanata/feature/glossary/InvalidGlossaryPushTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TestRule; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.util.SampleProjectRule; @@ -62,7 +63,8 @@ public void before() { userConfigPath = ClientWorkFlow.getUserConfigPath("glossarist"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + @Feature(summary = "Invalid glossary file will be rejected by the server") public void successfulGlossaryPush() throws Exception { List result = push(pushCommand, userConfigPath); log.info(resultByLines(result)); diff --git a/functional-test/src/test/java/org/zanata/feature/googleopenid/GoogleOpenIDTest.java b/functional-test/src/test/java/org/zanata/feature/googleopenid/GoogleOpenIDTest.java index 4628b60a6d..8a48d3c438 100644 --- a/functional-test/src/test/java/org/zanata/feature/googleopenid/GoogleOpenIDTest.java +++ b/functional-test/src/test/java/org/zanata/feature/googleopenid/GoogleOpenIDTest.java @@ -81,7 +81,7 @@ public void before() { assumeTrue(googleAccountPage.getUrl().contains("/ServiceLogin")); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void signInWithGoogleOpenID() { String googleUsername = googleUsername1; String googlePassword = googlePassword1; diff --git a/functional-test/src/test/java/org/zanata/feature/infrastructure/RetryRuleTest.java b/functional-test/src/test/java/org/zanata/feature/infrastructure/RetryRuleTest.java index 84ad277820..294a982364 100644 --- a/functional-test/src/test/java/org/zanata/feature/infrastructure/RetryRuleTest.java +++ b/functional-test/src/test/java/org/zanata/feature/infrastructure/RetryRuleTest.java @@ -41,7 +41,7 @@ public class RetryRuleTest extends ZanataTestCase { @Rule public RetryRule retryRule = new RetryRule(2); - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void retryPassAfterFail() { // Fail on the first execution, but pass on the second assertThat("Current try is greater than 1", retryRule.currentTry(), @@ -51,7 +51,7 @@ public void retryPassAfterFail() { Matchers.equalTo(2)); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void passWillPass() { assertThat("A normal passing test will pass", true); assertThat("And pass on the first try", retryRule.currentTry(), diff --git a/functional-test/src/test/java/org/zanata/feature/language/AddLanguageTest.java b/functional-test/src/test/java/org/zanata/feature/language/AddLanguageTest.java index 958ba8259f..bf56632a83 100644 --- a/functional-test/src/test/java/org/zanata/feature/language/AddLanguageTest.java +++ b/functional-test/src/test/java/org/zanata/feature/language/AddLanguageTest.java @@ -24,11 +24,10 @@ import java.util.List; import java.util.Map; -import org.hamcrest.Matchers; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.administration.AddLanguagePage; @@ -36,7 +35,7 @@ import org.zanata.util.SampleProjectRule; import org.zanata.workflow.LoginWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Damian Jansen enabledLocaleList = manageLanguagePage.goToHomePage() - .goToProjects() - .goToProject("about fedora") - .gotoVersion("master") - .gotoSettingsTab() - .gotoSettingsLanguagesTab() - .clickInheritCheckbox() - .waitForLocaleListVisible() - .getEnabledLocaleList(); - - assertThat("The language is enabled by default", enabledLocaleList, - Matchers.hasItem(languageDisplayName)); + List enabledLocaleList = manageLanguagePage + .goToHomePage() + .goToProjects() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsLanguagesTab() + .waitForLocaleListVisible() + .getEnabledLocaleList(); + + assertThat(enabledLocaleList) + .contains(languageDisplayName) + .as("The language is enabled by default"); } - @Test - public void addLanguageAsDisabled() { + @Feature(summary = "The administrator can add a disabled language to Zanata", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 181709) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void addLanguageAsDisabled() throws Exception { String language = "Klingon"; String languageDisplayName = "klingon[Klingon]"; - ManageLanguagePage manageLanguagePage = - new LoginWorkFlow().signIn("admin", "admin").goToHomePage() - .goToAdministration().goToManageLanguagePage(); + ManageLanguagePage manageLanguagePage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToHomePage() + .goToAdministration() + .goToManageLanguagePage(); - assertThat("The language is not listed", - manageLanguagePage.getLanguageLocales(), - Matchers.not(Matchers.hasItem(language))); + assertThat(manageLanguagePage.getLanguageLocales()) + .doesNotContain(language) + .as("The language is not listed"); - manageLanguagePage = - manageLanguagePage.addNewLanguage().inputLanguage(language) - .disableLanguageByDefault().saveLanguage(); + manageLanguagePage = manageLanguagePage + .addNewLanguage() + .inputLanguage(language) + .disableLanguageByDefault() + .saveLanguage(); - assertThat("The language is listed", - manageLanguagePage.getLanguageLocales(), - Matchers.hasItem(language)); - assertThat("The language is disabled by default", - !manageLanguagePage.languageIsEnabled(language)); + assertThat(manageLanguagePage.getLanguageLocales()) + .contains(language) + .as("The language is listed"); + assertThat(manageLanguagePage.languageIsEnabled(language)) + .isFalse() + .as("The language is disabled by default"); List enabledLocaleList = manageLanguagePage.goToHomePage() .goToProjects() - .goToProject("about fedora").gotoVersion("master") - .gotoSettingsTab().gotoSettingsLanguagesTab() - .clickInheritCheckbox() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsLanguagesTab() .waitForLocaleListVisible() .getEnabledLocaleList(); - assertThat("The language is disabled by default", enabledLocaleList, - Matchers.not(Matchers.hasItem(languageDisplayName))); + assertThat(enabledLocaleList) + .doesNotContain(languageDisplayName) + .as("The language is disabled by default"); } - @Test - public void addKnownLanguage() { + @Feature(summary = "The administrator can add a known language to Zanata", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 181709) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void addKnownLanguage() throws Exception { String language = "ru-RU"; - ManageLanguagePage manageLanguagePage = - new LoginWorkFlow().signIn("admin", "admin").goToHomePage() - .goToAdministration().goToManageLanguagePage(); + ManageLanguagePage manageLanguagePage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToHomePage() + .goToAdministration() + .goToManageLanguagePage(); - assertThat("The language is not listed", - manageLanguagePage.getLanguageLocales(), - Matchers.not(Matchers.hasItem(language))); + assertThat(manageLanguagePage.getLanguageLocales()) + .doesNotContain(language) + .as("The language is not listed"); - AddLanguagePage addLanguagePage = - manageLanguagePage.addNewLanguage().inputLanguage("ru-RU"); + AddLanguagePage addLanguagePage = manageLanguagePage + .addNewLanguage() + .inputLanguage("ru-RU"); Map languageInfo = addLanguagePage.getLanguageDetails(); - assertThat("The name is correct", languageInfo.get("Name"), - Matchers.equalTo("Russian (Russia)")); - assertThat("The native name is correct", - languageInfo.get("Native Name"), - Matchers.equalTo("русский (Россия)")); - assertThat("The language is correct", - languageInfo.get("Language Code"), Matchers.equalTo("ru")); - assertThat("The country code is correct", - languageInfo.get("Country Code"), Matchers.equalTo("RU")); + assertThat(languageInfo.get("Name")) + .isEqualTo("Russian (Russia)") + .as("The name is correct"); + assertThat(languageInfo.get("Native Name")) + .isEqualTo("русский (Россия)") + .as("The native name is correct"); + assertThat(languageInfo.get("Language Code")) + .isEqualTo("ru") + .as("The language is correct"); + assertThat(languageInfo.get("Country Code")) + .isEqualTo("RU") + .as("The country code is correct"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/language/JoinLanguageTeamTest.java b/functional-test/src/test/java/org/zanata/feature/language/JoinLanguageTeamTest.java index bd7602b3af..8631a5e823 100644 --- a/functional-test/src/test/java/org/zanata/feature/language/JoinLanguageTeamTest.java +++ b/functional-test/src/test/java/org/zanata/feature/language/JoinLanguageTeamTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.administration.ManageLanguageTeamMemberPage; @@ -36,8 +37,10 @@ @Category(DetailedTest.class) public class JoinLanguageTeamTest extends ZanataTestCase { - @Test - public void translatorJoinsLanguageTeam() { + @Feature(summary = "The administrator can add a member to a language team", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 181703) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void translatorJoinsLanguageTeam() throws Exception { ManageLanguageTeamMemberPage manageTeamMemberPage = new LoginWorkFlow() .signIn("admin", "admin") .goToAdministration() diff --git a/functional-test/src/test/java/org/zanata/feature/misc/ContactAdminTest.java b/functional-test/src/test/java/org/zanata/feature/misc/ContactAdminTest.java index c61bdb06e1..2fa9e0dd69 100644 --- a/functional-test/src/test/java/org/zanata/feature/misc/ContactAdminTest.java +++ b/functional-test/src/test/java/org/zanata/feature/misc/ContactAdminTest.java @@ -2,12 +2,12 @@ import java.util.List; -import org.hamcrest.Matchers; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.subethamail.wiser.WiserMessage; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.dashboard.DashboardBasePage; @@ -19,12 +19,9 @@ import org.zanata.util.PropertiesHolder; import org.zanata.workflow.LoginWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** - * TCMS test case 181717 - * * @author Patrick Huang pahuang@redhat.com */ @@ -33,41 +30,63 @@ public class ContactAdminTest extends ZanataTestCase { @Rule public AddUsersRule addUsersRule = new AddUsersRule(); - @ClassRule - public static HasEmailRule emailRule = new HasEmailRule(); + @Rule + public HasEmailRule emailRule = new HasEmailRule(); - @Test + @Feature(summary = "The user can contact the site administrator", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 181717) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void testContactAdmin() { DashboardBasePage dashboard = new LoginWorkFlow().signIn("translator", "translator"); ContactAdminFormPage contactAdminFormPage = dashboard.goToHelp().clickContactAdmin(); - HelpPage helpPage = - contactAdminFormPage.inputSubject("hello admin") - .inputMessage("I love Zanata").send(); + HelpPage helpPage = contactAdminFormPage + .inputSubject("hello admin") + .inputMessage("I love Zanata") + .send(); + + assertThat(helpPage.expectNotification("Your message has been sent " + + "to the administrator")) + .isTrue() + .as("An email sent notification shows"); - assertThat( - helpPage.getNotificationMessage(), - Matchers.equalTo("Your message has been sent to the administrator")); List messages = emailRule.getMessages(); - assertThat(messages, Matchers.hasSize(1)); + + assertThat(messages.size()) + .isEqualTo(1) + .as("One email was sent"); + WiserMessage wiserMessage = messages.get(0); - assertThat(wiserMessage.getEnvelopeReceiver(), - Matchers.equalTo("admin@example.com")); + + assertThat(wiserMessage.getEnvelopeReceiver()) + .isEqualTo("admin@example.com") + .as("The email recipient is the administrator"); String content = HasEmailRule.getEmailContent(wiserMessage); - assertThat( - content, - Matchers.containsString("Zanata user 'translator' with id 'translator' has sent the following message:")); - assertThat(content, Matchers.containsString("I love Zanata")); - assertThat( - content, - Matchers.containsString("You can reply to translator at translator@example.com")); + + assertThat(content) + .contains("Zanata user ") + .contains("translator") + .contains(" with id ") + .contains(" has sent the following message:") + .as("The email header is correct"); + assertThat(content) + .contains("I love Zanata") + .as("The message content is correct"); + assertThat(content) + .contains("You can reply to translator at " + + "translator@example.com") + .as("The email instructions are correct"); + // contains instance url (without last slash) - String instanceUrl = PropertiesHolder - .getProperty(Constants.zanataInstance.value()).replaceAll("/$", ""); - assertThat(content, Matchers.containsString(instanceUrl)); + String instanceUrl = PropertiesHolder.getProperty( + Constants.zanataInstance.value()).replaceAll("/$", ""); + + assertThat(content) + .contains(instanceUrl) + .as("The email origin (server) is correct"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/misc/ObsoleteTextTest.java b/functional-test/src/test/java/org/zanata/feature/misc/ObsoleteTextTest.java index 1d701f8aa6..0ede5f3d39 100644 --- a/functional-test/src/test/java/org/zanata/feature/misc/ObsoleteTextTest.java +++ b/functional-test/src/test/java/org/zanata/feature/misc/ObsoleteTextTest.java @@ -61,7 +61,7 @@ public void setUp() throws Exception { * 10. Enter translation editor for bem and see whether the project and document are 100%translated. * */ - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void obsoleteTextTest() { restCaller .createProjectAndVersion("obsolete-test", "master", "gettext"); diff --git a/functional-test/src/test/java/org/zanata/feature/misc/RateLimitRestAndUITest.java b/functional-test/src/test/java/org/zanata/feature/misc/RateLimitRestAndUITest.java index 8f2d28c015..eae4a4230d 100644 --- a/functional-test/src/test/java/org/zanata/feature/misc/RateLimitRestAndUITest.java +++ b/functional-test/src/test/java/org/zanata/feature/misc/RateLimitRestAndUITest.java @@ -10,12 +10,12 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.hamcrest.Matchers; import org.jboss.resteasy.client.ClientRequest; import org.jboss.resteasy.client.core.BaseClientResponse; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.administration.AdministrationPage; @@ -32,7 +32,7 @@ import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.model.HApplicationConfiguration.KEY_ADMIN_EMAIL; import static org.zanata.model.HApplicationConfiguration.KEY_MAX_ACTIVE_REQ_PER_API_KEY; import static org.zanata.model.HApplicationConfiguration.KEY_MAX_CONCURRENT_REQ_PER_API_KEY; @@ -43,6 +43,8 @@ * @author Patrick Huang pahuang@redhat.com */ +@Feature(summary = "The system can be set to rate consecutive REST access calls", + tcmsTestPlanIds = 5315, tcmsTestCaseIds = 0) @Category(DetailedTest.class) @Slf4j public class RateLimitRestAndUITest extends ZanataTestCase { @@ -57,7 +59,7 @@ public class RateLimitRestAndUITest extends ZanataTestCase { + KEY_MAX_CONCURRENT_REQ_PER_API_KEY; private String maxActivePathParam = "c/" + KEY_MAX_ACTIVE_REQ_PER_API_KEY; - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void canConfigureRateLimitByWebUI() { new LoginWorkFlow().signIn("admin", "admin"); BasicWorkFlow basicWorkFlow = new BasicWorkFlow(); @@ -65,27 +67,27 @@ public void canConfigureRateLimitByWebUI() { basicWorkFlow.goToPage("admin/server_configuration", ServerConfigurationPage.class); - assertThat(serverConfigPage.getMaxConcurrentRequestsPerApiKey(), - Matchers.isEmptyString()); - assertThat(serverConfigPage.getMaxActiveRequestsPerApiKey(), - Matchers.isEmptyString()); + assertThat(serverConfigPage.getMaxConcurrentRequestsPerApiKey()) + .isEqualTo("default is 6"); + assertThat(serverConfigPage.getMaxActiveRequestsPerApiKey()) + .isEqualTo("default is 2"); AdministrationPage administrationPage = serverConfigPage.inputMaxConcurrent(5).inputMaxActive(3).save(); - assertThat(administrationPage.getNotificationMessage(), - Matchers.equalTo("Configuration was successfully updated.")); + assertThat(administrationPage.getNotificationMessage()) + .isEqualTo("Configuration was successfully updated."); serverConfigPage = basicWorkFlow.goToPage("admin/server_configuration", ServerConfigurationPage.class); - assertThat(serverConfigPage.getMaxActiveRequestsPerApiKey(), - Matchers.equalTo("3")); - assertThat(serverConfigPage.getMaxConcurrentRequestsPerApiKey(), - Matchers.equalTo("5")); + assertThat(serverConfigPage.getMaxActiveRequestsPerApiKey()) + .isEqualTo("3"); + assertThat(serverConfigPage.getMaxConcurrentRequestsPerApiKey()) + .isEqualTo("5"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void canCallServerConfigurationRestService() throws Exception { ClientRequest clientRequest = clientRequestAsAdmin("rest/configurations/" @@ -94,20 +96,20 @@ public void canCallServerConfigurationRestService() throws Exception { // can put Response putResponse = clientRequest.put(); - assertThat(getStatusAndReleaseConnection(putResponse), Matchers.is(201)); + assertThat(getStatusAndReleaseConnection(putResponse)).isEqualTo(201); // can get single configuration Response getResponse = clientRequestAsAdmin( "rest/configurations/" + maxConcurrentPathParam).get(); - assertThat(getResponse.getStatus(), Matchers.is(200)); + assertThat(getResponse.getStatus()).isEqualTo(200); String rateLimitConfig = ((BaseClientResponse) getResponse) .getEntity(String.class); - assertThat(rateLimitConfig, - Matchers.containsString(KEY_MAX_CONCURRENT_REQ_PER_API_KEY)); - assertThat(rateLimitConfig, Matchers.containsString("1")); + assertThat(rateLimitConfig) + .contains(KEY_MAX_CONCURRENT_REQ_PER_API_KEY); + assertThat(rateLimitConfig).contains("1"); // can get all configurations Response getAllResponse = @@ -118,9 +120,9 @@ public void canCallServerConfigurationRestService() throws Exception { String configurations = baseClientResponse.getEntity(String.class); log.info("result {}", configurations); - assertThat(getStatusAndReleaseConnection(getAllResponse), - Matchers.is(200)); - assertThat(configurations, Matchers.notNullValue()); + assertThat(getStatusAndReleaseConnection(getAllResponse)) + .isEqualTo(200); + assertThat(configurations).isNotNull(); } private static ClientRequest clientRequestAsAdmin(String path) { @@ -135,25 +137,25 @@ private static ClientRequest clientRequestAsAdmin(String path) { return clientRequest; } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void serverConfigurationRestServiceOnlyAvailableToAdmin() throws Exception { // all request should be rejected Response response = clientRequestAsTranslator("rest/configurations/").get(); - assertThat(getStatusAndReleaseConnection(response), Matchers.is(401)); + assertThat(getStatusAndReleaseConnection(response)).isEqualTo(401); Response response1 = clientRequestAsTranslator( "rest/configurations/c/" + KEY_ADMIN_EMAIL).get(); - assertThat(getStatusAndReleaseConnection(response1), Matchers.is(401)); + assertThat(getStatusAndReleaseConnection(response1)).isEqualTo(401); ClientRequest request = clientRequestAsTranslator("rest/configurations/c/" + KEY_ADMIN_EMAIL); request.body("text/plain", "admin@email.com"); Response response2 = request.put(); - assertThat(getStatusAndReleaseConnection(response2), Matchers.is(401)); + assertThat(getStatusAndReleaseConnection(response2)).isEqualTo(401); } private static ClientRequest clientRequestAsTranslator(String path) { @@ -167,20 +169,20 @@ private static ClientRequest clientRequestAsTranslator(String path) { return clientRequest; } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void canOnlyDealWithKnownConfiguration() throws Exception { ClientRequest clientRequest = clientRequestAsAdmin("rest/configurations/c/abc"); Response putResponse = clientRequest.put(); - assertThat(getStatusAndReleaseConnection(putResponse), Matchers.is(400)); + assertThat(getStatusAndReleaseConnection(putResponse)).isEqualTo(400); Response getResponse = clientRequestAsAdmin("rest/configurations/c/abc").get(); - assertThat(getStatusAndReleaseConnection(getResponse), Matchers.is(404)); + assertThat(getStatusAndReleaseConnection(getResponse)).isEqualTo(404); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void canLimitConcurrentRestRequestsPerAPIKey() throws Exception { // translator creates the project/version final String projectSlug = "project"; @@ -238,7 +240,7 @@ ImmutableList.> builder() // 1 request from translator should get 403 and fail log.info("result: {}", result); - assertThat(result, Matchers.containsInAnyOrder(201, 201, 201, 201, 429)); + assertThat(result).contains(201, 201, 201, 201, 429); } @Test(timeout = 5000) @@ -260,7 +262,7 @@ public void exceptionWillReleaseSemaphore() throws Exception { // Then: request that result in exception should still release // semaphore. i.e. no permit leak - assertThat(1, Matchers.is(1)); + assertThat(1).isEqualTo(1); } @Test(timeout = 5000) @@ -282,7 +284,7 @@ public void unmappedExceptionWillAlsoReleaseSemaphore() throws Exception { // Then: request that result in exception should still release // semaphore. i.e. no permit leak - assertThat(1, Matchers.is(1)); + assertThat(1).isEqualTo(1); } private static Integer invokeRestService(ZanataRestCaller restCaller, diff --git a/functional-test/src/test/java/org/zanata/feature/project/CreateProjectTest.java b/functional-test/src/test/java/org/zanata/feature/project/CreateProjectTest.java index 698773a79f..3d6dd88555 100644 --- a/functional-test/src/test/java/org/zanata/feature/project/CreateProjectTest.java +++ b/functional-test/src/test/java/org/zanata/feature/project/CreateProjectTest.java @@ -22,11 +22,11 @@ package org.zanata.feature.project; import java.util.HashMap; -import java.util.List; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; import org.zanata.feature.testharness.TestPlan.DetailedTest; @@ -36,9 +36,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; +import static org.assertj.core.api.Assertions.assertThat; import static org.zanata.workflow.ProjectWorkFlow.projectDefaults; /** @@ -51,47 +49,46 @@ public class CreateProjectTest extends ZanataTestCase { @ClassRule public static AddUsersRule addUsersRule = new AddUsersRule(); - @Test + @Feature(summary = "The user can create a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 144262) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) @Category(BasicAcceptanceTest.class) - public void createABasicProject() { - - assertThat("User logs in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - equalTo("admin")); + public void createABasicProject() throws Exception { + assertThat(new LoginWorkFlow().signIn("admin", "admin").loggedInAs()) + .isEqualTo("admin") + .as("User logs in"); ProjectVersionsPage projectVersionsPage = new ProjectWorkFlow() .createNewSimpleProject("basicproject", "basicproject"); - assertThat("The project name is correct", - projectVersionsPage.getProjectName().trim(), - equalTo("basicproject")); + assertThat(projectVersionsPage.getProjectName().trim()) + .isEqualTo("basicproject") + .as("The project name is correct"); } - @Test - public void createABasicProjectWithHomepageContent() { - + @Feature(summary = "The user can create a project with description", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 144262) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void createABasicProjectWithDescription() throws Exception { HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "homepageproject"); - projectSettings.put("Name", "Project With Homepage Test"); + projectSettings.put("Project ID", "descriptionproject"); + projectSettings.put("Name", "Project With Description Test"); projectSettings.put("Description", "Project Description!"); - assertThat("Admin can log in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - equalTo("admin")); + assertThat(new LoginWorkFlow().signIn("admin", "admin").loggedInAs()) + .isEqualTo("admin") + .as("Admin can log in"); ProjectBasePage projectPage = new ProjectWorkFlow().createNewProject(projectSettings); - assertThat("The project name is correct", - projectPage.getProjectName().trim(), - equalTo(projectSettings.get("Name"))); - - List paragraphs = projectPage.getContentAreaParagraphs(); - - assertThat("The project content area shows the description", - paragraphs, - hasItem(projectSettings.get("Description"))); + assertThat(projectPage.getProjectName().trim()) + .isEqualTo(projectSettings.get("Name")) + .as("The project name is correct"); + assertThat(projectPage.getContentAreaParagraphs()) + .contains(projectSettings.get("Description")) + .as("The project content area shows the description"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/project/EditPermissionsTest.java b/functional-test/src/test/java/org/zanata/feature/project/EditPermissionsTest.java index 5161f6d2d6..49a764efb0 100644 --- a/functional-test/src/test/java/org/zanata/feature/project/EditPermissionsTest.java +++ b/functional-test/src/test/java/org/zanata/feature/project/EditPermissionsTest.java @@ -21,17 +21,16 @@ package org.zanata.feature.project; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.not; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.page.projects.ProjectBasePage; import org.zanata.page.projects.ProjectMaintainersPage; import org.zanata.page.projects.projectsettings.ProjectPermissionsTab; import org.zanata.page.projects.ProjectVersionsPage; @@ -49,73 +48,78 @@ public class EditPermissionsTest extends ZanataTestCase { @Rule public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - @Test - public void maintainerDetailsAreDisplayed() { - ProjectPermissionsTab projectPermissionsTab = - new LoginWorkFlow() - .signIn("admin", "admin") - .goToProjects() - .goToProject("about fedora") - .gotoSettingsTab() - .gotoSettingsPermissionsTab(); + @Feature(summary = "The user can view maintainers for a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void maintainerDetailsAreDisplayed() throws Exception { + ProjectPermissionsTab projectPermissionsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsPermissionsTab(); - assertThat("The admin user is shown in the list", - projectPermissionsTab.getSettingsMaintainersList(), - hasItem("admin")); + assertThat(projectPermissionsTab.getSettingsMaintainersList()) + .contains("admin") + .as("The admin user is shown in the list"); ProjectMaintainersPage projectMaintainersPage = projectPermissionsTab .gotoMaintainersTab(); - assertThat("The admin user is shown in the list", - projectMaintainersPage.getMaintainers(), - hasItem("Administrator @admin")); + assertThat(projectMaintainersPage.getMaintainers()) + .contains("Administrator @admin") + .as("The admin user is shown in the list"); } - @Test - @Ignore("rhbz1097030") - public void addMaintainerAsAdmin() { - ProjectPermissionsTab projectPermissionsTab = - new LoginWorkFlow() - .signIn("admin", "admin") - .goToProjects() - .goToProject("about fedora") - .gotoSettingsTab() - .gotoSettingsPermissionsTab(); - - assertThat("The translator user is not a maintainer", - projectPermissionsTab.getSettingsMaintainersList(), - not(hasItem("translator"))); + @Feature(summary = "The administrator can add a maintainer to a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void addMaintainerAsAdmin() throws Exception { + ProjectPermissionsTab projectPermissionsTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsPermissionsTab(); + + assertThat(projectPermissionsTab.getSettingsMaintainersList()) + .doesNotContain("translator") + .as("The translator user is not a maintainer"); projectPermissionsTab = new ProjectWorkFlow() .addMaintainer("about fedora", "translator"); - assertThat("The translator user is a maintainer", - projectPermissionsTab.getSettingsMaintainersList(), - hasItem("translator")); + assertThat(projectPermissionsTab.getSettingsMaintainersList()) + .contains("translator") + .as("The translator user is a maintainer"); ProjectMaintainersPage projectMaintainersPage = projectPermissionsTab .gotoMaintainersTab(); - assertThat("The translator user is shown in the list", - projectMaintainersPage.getMaintainers(), - hasItem("translator @translator")); + assertThat(projectMaintainersPage.getMaintainers()) + .contains("translator @translator") + .as("The translator user is shown in the list"); projectMaintainersPage.logout(); - assertThat("The settings tab is now available to the user", - new LoginWorkFlow().signIn("translator", "translator") - .goToProjects() - .goToProject("about fedora") - .settingsTabIsDisplayed()); + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .goToProjects() + .goToProject("about fedora") + .settingsTabIsDisplayed()) + .isTrue() + .as("The settings tab is now available to the user"); } - @Test - @Ignore("rhbz1097030") - public void addMaintainerAsMaintainer() { - - assertThat("Translator has signed in", - new LoginWorkFlow().signIn("translator", "translator").loggedInAs(), - equalTo("translator")); + @Feature(summary = "The maintainer can add a maintainer to a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 199006) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void addMaintainerAsMaintainer() throws Exception { + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .loggedInAs()) + .isEqualTo("translator") + .as("Translator has signed in"); ProjectPermissionsTab projectPermissionsTab = new ProjectWorkFlow() .createNewSimpleProject("addmaintainer", "addmaintainer") @@ -126,16 +130,16 @@ public void addMaintainerAsMaintainer() { projectPermissionsTab.waitForMaintainersContains("glossarist"); - assertThat("The glossarist user was added as a maintainer", - projectPermissionsTab.getSettingsMaintainersList(), - hasItem("glossarist")); + assertThat(projectPermissionsTab.getSettingsMaintainersList()) + .contains("glossarist") + .as("The glossarist user was added as a maintainer"); ProjectMaintainersPage projectMaintainersPage = projectPermissionsTab .gotoMaintainersTab(); - assertThat("The glossarist user is shown in the list", - projectMaintainersPage.getMaintainers(), - hasItem("glossarist @glossarist")); + assertThat(projectMaintainersPage.getMaintainers()) + .contains("glossarist @glossarist") + .as("The glossarist user is shown in the list"); projectMaintainersPage.logout(); @@ -144,78 +148,85 @@ public void addMaintainerAsMaintainer() { .goToProjects() .goToProject("addmaintainer"); - assertThat("The settings tab is now available to the glossarist", - projectVersionsPage.settingsTabIsDisplayed()); + assertThat(projectVersionsPage.settingsTabIsDisplayed()) + .isTrue() + .as("The settings tab is now available to the glossarist"); } - @Test - @Ignore("rhbz1097030") - public void removeMaintainer() { - - assertThat("Translator has signed in", - new LoginWorkFlow().signIn("translator", "translator").loggedInAs(), - equalTo("translator")); - - assertThat("The project is created", - new ProjectWorkFlow() - .createNewSimpleProject("removemaintainer", - "removemaintainer") - .getProjectName(), - equalTo("removemaintainer")); - - assertThat("Glossarist maintainer is added", - new ProjectWorkFlow() - .addMaintainer("removemaintainer", "glossarist") - .getSettingsMaintainersList(), - hasItem("glossarist")); - + @Feature(summary = "The maintainer can remove a maintainer from a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 321234) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void removeMaintainer() throws Exception { + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .loggedInAs()) + .isEqualTo("translator") + .as("Translator has signed in"); + + assertThat(new ProjectWorkFlow() + .createNewSimpleProject("removemaintainer", "removemaintainer") + .getProjectName()) + .isEqualTo("removemaintainer") + .as("The project is created"); + + assertThat(new ProjectWorkFlow() + .addMaintainer("removemaintainer", "glossarist") + .getSettingsMaintainersList()) + .contains("glossarist") + .as("Glossarist maintainer is added"); ProjectPermissionsTab projectPermissionsTab = new ProjectWorkFlow() .removeMaintainer("removemaintainer", "glossarist"); - assertThat("Glossarist maintainer is removed", - projectPermissionsTab.getSettingsMaintainersList(), - not(hasItem("glossarist"))); + assertThat(projectPermissionsTab.getSettingsMaintainersList()) + .doesNotContain("glossarist") + .as("Glossarist maintainer is removed"); ProjectMaintainersPage projectMaintainersPage = projectPermissionsTab .gotoMaintainersTab(); - assertThat("The glossarist user is not in the list", - projectMaintainersPage.getMaintainers(), - not(hasItem("Glossarist @glossarist"))); + assertThat(projectMaintainersPage.getMaintainers()) + .doesNotContain("Glossarist @glossarist") + .as("The glossarist user is not in the list"); } - - @Test - @Ignore("Exception on self removal") - public void removeSelfAsMaintainer() { - - assertThat("Translator has signed in", - new LoginWorkFlow().signIn("translator", "translator").loggedInAs(), - equalTo("translator")); - - assertThat("The project is created", - new ProjectWorkFlow() - .createNewSimpleProject("removemaintainer", - "removemaintainer") - .getProjectName(), - equalTo("removemaintainer")); + @Feature(summary = "The maintainer can remove themselves as maintainer " + + "from a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Ignore("Exception thrown on removing self") + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void removeSelfAsMaintainer() throws Exception { + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .loggedInAs()) + .isEqualTo("translator") + .as("Translator has signed in"); + + assertThat(new ProjectWorkFlow() + .createNewSimpleProject("removemaintainer", "removemaintainer") + .getProjectName()) + .isEqualTo("removemaintainer") + .as("The project is created"); ProjectPermissionsTab projectPermissionsTab = new ProjectWorkFlow() .addMaintainer("removemaintainer", "admin"); - assertThat("admin maintainer is added", - projectPermissionsTab.getSettingsMaintainersList(), - hasItem("admin")); + assertThat(projectPermissionsTab.getSettingsMaintainersList()) + .contains("admin") + .as("admin maintainer is added"); - ProjectVersionsPage projectVersionsPage = projectPermissionsTab - .clickRemoveOnSelf("translator") - .goToHomePage().goToProjects() + projectPermissionsTab.slightPause(); + ProjectBasePage projectBasePage = projectPermissionsTab + .clickRemoveOnSelf("translator"); + projectBasePage.slightPause(); + ProjectVersionsPage projectVersionsPage = projectBasePage + .goToHomePage() + .goToProjects() .goToProject("removemaintainer"); - assertThat("The translator user is no longer a maintainer", - projectVersionsPage.settingsTabIsDisplayed(), - not(true)); + assertThat(projectVersionsPage.settingsTabIsDisplayed()) + .isFalse() + .as("The translator user is no longer a maintainer"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/project/EditProjectAboutTest.java b/functional-test/src/test/java/org/zanata/feature/project/EditProjectAboutTest.java index b670180f90..9198a7f287 100644 --- a/functional-test/src/test/java/org/zanata/feature/project/EditProjectAboutTest.java +++ b/functional-test/src/test/java/org/zanata/feature/project/EditProjectAboutTest.java @@ -21,9 +21,10 @@ package org.zanata.feature.project; -import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projects.ProjectAboutPage; @@ -32,9 +33,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Damian Jansen @@ -43,36 +42,39 @@ @Category(DetailedTest.class) public class EditProjectAboutTest extends ZanataTestCase { - @ClassRule - public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); - - @Test - public void addAboutPageDetails() { + @Rule + public SampleProjectRule sampleProjectRule = new SampleProjectRule(); + @Feature(summary = "The administrator can change a project about content", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void addAboutPageDetails() throws Exception { String aboutText = "This is my about text for AF"; - assertThat("Admin is logged in", new LoginWorkFlow() + assertThat(new LoginWorkFlow() .signIn("admin", "admin") - .loggedInAs(), - equalTo("admin")); + .loggedInAs()) + .isEqualTo("admin") + .as("Admin is logged in"); ProjectAboutTab projectAboutTab = new ProjectWorkFlow() .createNewSimpleProject("aboutpagetest", "aboutpagetest") .gotoSettingsTab() .gotoSettingsAboutTab(); - assertThat("The text is empty", - projectAboutTab.getAboutText(), - isEmptyOrNullString()); + assertThat(projectAboutTab.getAboutText()) + .as("The text is empty") + .isNullOrEmpty(); - projectAboutTab = projectAboutTab.clearAboutText() + projectAboutTab = projectAboutTab + .clearAboutText() .enterAboutText(aboutText) .pressSave(); - //TODO waitForNotification + projectAboutTab.expectNotification("Successfully updated"); ProjectAboutPage projectAboutPage = projectAboutTab.gotoAboutTab(); - assertThat("The text in the About tab is correct", - projectAboutPage.getAboutText(), - equalTo(aboutText)); + assertThat(projectAboutPage.getAboutText()) + .isEqualTo(aboutText) + .as("The text in the About tab is correct"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/project/EditProjectGeneralTest.java b/functional-test/src/test/java/org/zanata/feature/project/EditProjectGeneralTest.java index 67457bcada..fabb4ea1bc 100644 --- a/functional-test/src/test/java/org/zanata/feature/project/EditProjectGeneralTest.java +++ b/functional-test/src/test/java/org/zanata/feature/project/EditProjectGeneralTest.java @@ -20,27 +20,20 @@ */ package org.zanata.feature.project; -import org.hamcrest.Matchers; -import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projects.projectsettings.ProjectGeneralTab; import org.zanata.page.projects.ProjectVersionsPage; import org.zanata.page.projects.ProjectsPage; -import org.zanata.util.AddUsersRule; +import org.zanata.util.SampleProjectRule; import org.zanata.workflow.BasicWorkFlow; import org.zanata.workflow.LoginWorkFlow; -import org.zanata.workflow.ProjectWorkFlow; -import java.util.HashMap; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; -import static org.zanata.workflow.ProjectWorkFlow.projectDefaults; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Damian Jansen @@ -49,78 +42,65 @@ @Category(DetailedTest.class) public class EditProjectGeneralTest extends ZanataTestCase { - @ClassRule - public static AddUsersRule addUsersRule = new AddUsersRule(); - - @Test - public void setAProjectToReadOnly() { - - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "deactivateproject"); - projectSettings.put("Name", "Deactivate Project Test"); - - assertThat("Admin can log in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - equalTo("admin")); + @Rule + public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - new ProjectWorkFlow() - .createNewProject(projectSettings) + @Feature(summary = "The administrator can set a project to read-only", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 135848) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void setAProjectToReadOnly() throws Exception { + ProjectsPage projectsPage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") .gotoSettingsTab() .gotoSettingsGeneral() - .lockProject(); - - ProjectsPage projectsPage = new BasicWorkFlow() - .goToHome() + .lockProject() .goToProjects() .setActiveFilterEnabled(true) .setReadOnlyFilterEnabled(false) .setObsoleteFilterEnabled(false) - .waitForProjectVisibility(projectSettings.get("Name"), false); + .waitForProjectVisibility("about fedora", false); - assertThat("The project is not displayed", - projectsPage.getProjectNamesOnCurrentPage(), - not(hasItem(projectSettings.get("Name")))); + assertThat(projectsPage.getProjectNamesOnCurrentPage()) + .doesNotContain("about fedora") + .as("The project is not displayed"); projectsPage = projectsPage.setActiveFilterEnabled(false) .setReadOnlyFilterEnabled(true) .setObsoleteFilterEnabled(false) - .waitForProjectVisibility(projectSettings.get("Name"), true); + .waitForProjectVisibility("about fedora", true); - assertThat("The project is now displayed", - projectsPage.getProjectNamesOnCurrentPage(), - hasItem(projectSettings.get("Name"))); + assertThat(projectsPage.getProjectNamesOnCurrentPage()) + .contains("about fedora") + .as("The project is now displayed"); } - @Test - public void setAProjectToWritable() { - - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "rewritableproject"); - projectSettings.put("Name", "Rewrite Project Test"); - - assertThat("Admin can log in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - equalTo("admin")); - - assertThat("The project is locked", - new ProjectWorkFlow() - .createNewProject(projectSettings) - .gotoSettingsTab() - .gotoSettingsGeneral() - .lockProject() - .goToProjects() - .setActiveFilterEnabled(false) - .setReadOnlyFilterEnabled(true) - .setObsoleteFilterEnabled(false) - .waitForProjectVisibility( - projectSettings.get("Name"), true) - .getProjectNamesOnCurrentPage(), - hasItem(projectSettings.get("Name"))); + @Feature(summary = "The administrator can set a read-only project " + + "to writable", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void setAProjectToWritable() throws Exception { + assertThat(new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsGeneral() + .lockProject() + .goToProjects() + .setActiveFilterEnabled(false) + .setReadOnlyFilterEnabled(true) + .setObsoleteFilterEnabled(false) + .waitForProjectVisibility("about fedora", true) + .getProjectNamesOnCurrentPage()) + .contains("about fedora") + .as("The project is locked"); ProjectsPage projectsPage = new BasicWorkFlow() .goToHome() .goToProjects() - .goToProject(projectSettings.get("Name")) + .goToProject("about fedora") .gotoSettingsTab() .gotoSettingsGeneral() .unlockProject() @@ -128,134 +108,93 @@ public void setAProjectToWritable() { .setActiveFilterEnabled(true) .setReadOnlyFilterEnabled(false) .setObsoleteFilterEnabled(false) - .waitForProjectVisibility(projectSettings.get("Name"), true); + .waitForProjectVisibility("about fedora", true); - assertThat("The project is now displayed", - projectsPage.getProjectNamesOnCurrentPage(), - hasItem(projectSettings.get("Name"))); + assertThat(projectsPage.getProjectNamesOnCurrentPage()) + .contains("about fedora") + .as("The project is now displayed"); } - @Test - public void setAProjectObsolete() { - - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "setobsoleteproject"); - projectSettings.put("Name", "Obsolete Project Test"); - projectSettings.put("Project Type", "File"); - - assertThat("Translator can log in", - new LoginWorkFlow() - .signIn("translator", "translator") - .loggedInAs(), - equalTo("translator")); - - assertThat("Archiving is not available to non admin", - new ProjectWorkFlow() - .createNewProject(projectSettings) - .gotoSettingsTab() - .gotoSettingsGeneral() - .isArchiveButtonAvailable(), - not(true)); - - new BasicWorkFlow().goToHome().logout(); - + @Feature(summary = "The administrator can set a project to obsolete", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 135846) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void setAProjectObsolete() throws Exception { ProjectsPage projectsPage = new LoginWorkFlow() .signIn("admin", "admin") .goToProjects() - .goToProject(projectSettings.get("Name")) + .goToProject("about fedora") .gotoSettingsTab() .gotoSettingsGeneral() .archiveProject() .goToProjects(); - assertThat("The project is not displayed", - projectsPage.getProjectNamesOnCurrentPage(), - not(hasItem(projectSettings.get("Name")))); + assertThat(projectsPage.getProjectNamesOnCurrentPage()) + .doesNotContain("about fedora") + .as("The project is not displayed"); projectsPage = projectsPage.setActiveFilterEnabled(false) .setReadOnlyFilterEnabled(false) .setObsoleteFilterEnabled(true); - projectsPage - .waitForProjectVisibility(projectSettings.get("Name"), true); + projectsPage.waitForProjectVisibility("about fedora", true); - assertThat("The project is now displayed", - projectsPage.getProjectNamesOnCurrentPage(), - hasItem(projectSettings.get("Name"))); + assertThat(projectsPage.getProjectNamesOnCurrentPage()) + .contains("about fedora") + .as("The project is now displayed"); projectsPage.logout(); - assertThat("User cannot navigate to a project", - new LoginWorkFlow() - .signIn("translator", "translator") - .goToProjects() - .getProjectNamesOnCurrentPage(), - not(hasItem(projectSettings.get("Name")))); + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .goToProjects() + .getProjectNamesOnCurrentPage()) + .doesNotContain("about fedora") + .as("User cannot navigate to the obsolete project"); } - @Test - public void setAnObsoleteProjectAsActive() { - - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "setobsoleteprojectactive"); - projectSettings.put("Name", "Unobsolete Project Test"); - projectSettings.put("Project Type", "File"); - - assertThat("Translator can log in", - new LoginWorkFlow() - .signIn("translator", "translator") - .loggedInAs(), - equalTo("translator")); - - new ProjectWorkFlow() - .createNewProject(projectSettings) + @Feature(summary = "The administrator can set an obsolete project " + + "to active", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void setAnObsoleteProjectAsActive() throws Exception { + ProjectGeneralTab projectGeneralTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") .gotoSettingsTab() .gotoSettingsGeneral() - .logout(); - - ProjectGeneralTab projectGeneralTab = - new LoginWorkFlow() - .signIn("admin", "admin") - .goToProjects() - .goToProject(projectSettings.get("Name")) - .gotoSettingsTab() - .gotoSettingsGeneral() - .archiveProject() - .goToProjects() - .setObsoleteFilterEnabled(true) - .goToProject(projectSettings.get("Name")) - .gotoSettingsTab() - .gotoSettingsGeneral() - .unarchiveProject(); - - assertThat("The archive button is now available", - projectGeneralTab.isArchiveButtonAvailable()); - - assertThat("Translator can view the project", - new LoginWorkFlow() - .signIn("translator", "translator") - .goToProjects() - .goToProject(projectSettings.get("Name")) - .getProjectName(), - equalTo(projectSettings.get("Name"))); - - } + .archiveProject() + .goToProjects() + .setObsoleteFilterEnabled(true) + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsGeneral() + .unarchiveProject(); - @Test - public void changeProjectName() { + assertThat(projectGeneralTab.isArchiveButtonAvailable()) + .isTrue() + .as("The archive button is now available"); - String replacementText = "a new name"; - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "changeName"); - projectSettings.put("Name", "Project Name Change Test"); + projectGeneralTab.logout(); - assertThat("Admin can log in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - Matchers.equalTo("admin")); + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .goToProjects() + .goToProject("about fedora") + .getProjectName()) + .isEqualTo("about fedora") + .as("Translator can view the project"); + } - ProjectVersionsPage projectVersionsPage = - new ProjectWorkFlow() - .createNewProject(projectSettings) + @Feature(summary = "The administrator can change a project's name", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 198431) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeProjectName() throws Exception { + String replacementText = "a new name"; + ProjectVersionsPage projectVersionsPage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") .gotoSettingsTab() .gotoSettingsGeneral() .enterProjectName(replacementText) @@ -263,93 +202,81 @@ public void changeProjectName() { .goToProjects() .goToProject(replacementText); - assertThat("The name has changed", - projectVersionsPage.getProjectName(), - Matchers.equalTo(replacementText)); + assertThat(projectVersionsPage.getProjectName()) + .isEqualTo(replacementText) + .as("The project name has changed"); } - @Test - public void changeProjectDescription() { - + @Feature(summary = "The administrator can change a project's description", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 198431) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeProjectDescription() throws Exception { String replacementText = "a new description"; - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "changeDescription"); - projectSettings.put("Name", "Project Description Test"); - projectSettings.put("Description", "An old description"); - - assertThat("Admin can log in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - Matchers.equalTo("admin")); - - ProjectVersionsPage projectVersionsPage = - new ProjectWorkFlow() - .createNewProject(projectSettings) + ProjectVersionsPage projectVersionsPage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora"); + + assertThat(projectVersionsPage.getContentAreaParagraphs()) + .doesNotContain(replacementText) + .as("The description is default"); + + ProjectGeneralTab projectGeneralTab = projectVersionsPage .gotoSettingsTab() .gotoSettingsGeneral() .enterDescription(replacementText) - .updateProject() - .goToProjects() - .goToProject(projectSettings.get("Name")); + .updateProject(); - assertThat("The text has changed", - projectVersionsPage.getContentAreaParagraphs(), - Matchers.hasItem(replacementText)); + assertThat(projectGeneralTab.getContentAreaParagraphs()) + .contains(replacementText) + .as("The text has changed"); } - @Test - public void changeProjectType() { - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "changeType"); - projectSettings.put("Name", "Project Type Test"); - - assertThat("Admin can log in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - Matchers.equalTo("admin")); - - ProjectGeneralTab projectGeneralTab = - new ProjectWorkFlow() - .createNewProject(projectSettings) + @Feature(summary = "The administrator can change a project's type", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 198431) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeProjectType() throws Exception { + ProjectGeneralTab projectGeneralTab = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") .gotoSettingsTab() .gotoSettingsGeneral() .selectProjectType("Properties") - .updateProject() - .goToProjects() - .goToProject(projectSettings.get("Name")) + .updateProject(); + + projectGeneralTab.reload(); + projectGeneralTab = projectGeneralTab .gotoSettingsTab() .gotoSettingsGeneral(); - assertThat("The type is correct", - projectGeneralTab.getSelectedProjectType(), - Matchers.equalTo("Properties")); + assertThat(projectGeneralTab.getSelectedProjectType()) + .isEqualTo("Properties") + .as("The project type is correct"); } - @Test - public void changeSourceLinks() { - HashMap projectSettings = projectDefaults(); - projectSettings.put("Project ID", "changeLinks"); - projectSettings.put("Name", "Project Links Test"); - - assertThat("Admin can log in", - new LoginWorkFlow().signIn("admin", "admin").loggedInAs(), - Matchers.equalTo("admin")); - - ProjectVersionsPage projectVersionsPage = - new ProjectWorkFlow() - .createNewProject(projectSettings) + @Feature(summary = "The administrator can change a project's source urls", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 198431) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void changeSourceLinks() throws Exception { + ProjectVersionsPage projectVersionsPage = new LoginWorkFlow() + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") .gotoSettingsTab() .gotoSettingsGeneral() .enterHomePage("http://www.example.com") .enterRepository("http://www.test.com") .updateProject() .goToProjects() - .goToProject(projectSettings.get("Name")); + .goToProject("about fedora"); - assertThat("The homepage is correct", - projectVersionsPage.getHomepage(), - Matchers.equalTo("http://www.example.com")); + assertThat(projectVersionsPage.getHomepage()) + .isEqualTo("http://www.example.com") + .as("The homepage is correct"); - assertThat("The git url is correct", - projectVersionsPage.getGitUrl(), - Matchers.equalTo("http://www.test.com")); + assertThat(projectVersionsPage.getGitUrl()) + .isEqualTo("http://www.test.com") + .as("The git url is correct"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/project/EditProjectLanguagesTest.java b/functional-test/src/test/java/org/zanata/feature/project/EditProjectLanguagesTest.java index d70af91596..857d2598b8 100644 --- a/functional-test/src/test/java/org/zanata/feature/project/EditProjectLanguagesTest.java +++ b/functional-test/src/test/java/org/zanata/feature/project/EditProjectLanguagesTest.java @@ -21,20 +21,21 @@ package org.zanata.feature.project; -import org.junit.ClassRule; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.assertj.core.api.Assertions; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.page.projects.projectsettings.ProjectLanguagesTab; import org.zanata.util.SampleProjectRule; import org.zanata.workflow.LoginWorkFlow; -import java.util.List; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - /** * @author Damian Jansen * djansen@redhat.com @@ -42,11 +43,13 @@ @Category(DetailedTest.class) public class EditProjectLanguagesTest extends ZanataTestCase { - @ClassRule - public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); + @Rule + public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - @Test - public void editProjectLanguages() { + @Feature(summary = "The administrator can edit the project languages", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void editProjectLanguages() throws Exception { ProjectLanguagesTab projectLanguagesTab = new LoginWorkFlow() .signIn("admin", "admin") .goToProjects() @@ -54,17 +57,19 @@ public void editProjectLanguages() { .gotoSettingsTab() .gotoSettingsLanguagesTab(); + projectLanguagesTab.slightPause(); + List enabledLocaleList = projectLanguagesTab .getEnabledLocaleList(); - assertThat("The enabled list contains three languages", - enabledLocaleList, - contains("French[fr]", "Hindi[hi]", "Polish[pl]")); + assertThat(enabledLocaleList) + .contains("French[fr]", "Hindi[hi]", "Polish[pl]") + .as("The enabled list contains three languages"); - assertThat("The enabled list does not contain " + - "'English (United States)[en-US]'", - enabledLocaleList, - not(hasItem("English (United States)[en-US]"))); + assertThat(enabledLocaleList) + .doesNotContain("English (United States)[en-US]") + .as("The enabled list does not contain " + + "'English (United States)[en-US]'"); projectLanguagesTab = projectLanguagesTab .gotoSettingsTab() @@ -76,13 +81,10 @@ public void editProjectLanguages() { .gotoSettingsLanguagesTab() .getEnabledLocaleList(); - assertThat("The enabled list does not contain 'US English'", - enabledLocaleList, - not(hasItem("English (United States)[en-US]"))); - - assertThat("The enabled list does not contain 'Polish'", - enabledLocaleList, - not(hasItem("Polish[pl]"))); + assertThat(enabledLocaleList) + .doesNotContain("English (United States)[en-US]") + .doesNotContain("Polish[pl]") + .as("The enabled list does not contain 'US English' or Polish"); enabledLocaleList = projectLanguagesTab .gotoSettingsTab() @@ -91,10 +93,10 @@ public void editProjectLanguages() { .addLanguage("English (United States)[en-US]") .getEnabledLocaleList(); - assertThat("Three languages are available to translate", - enabledLocaleList, - contains("English (United States)[en-US]", + Assertions.assertThat(enabledLocaleList) + .contains("English (United States)[en-US]", "French[fr]", - "Hindi[hi]")); + "Hindi[hi]") + .as("The enabled language list contains en-US, fr and hi"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/project/EditProjectValidationsTest.java b/functional-test/src/test/java/org/zanata/feature/project/EditProjectValidationsTest.java index 5894c462c3..d81610920f 100644 --- a/functional-test/src/test/java/org/zanata/feature/project/EditProjectValidationsTest.java +++ b/functional-test/src/test/java/org/zanata/feature/project/EditProjectValidationsTest.java @@ -23,13 +23,14 @@ import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projects.projectsettings.ProjectTranslationTab; import org.zanata.util.SampleProjectRule; import org.zanata.workflow.LoginWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; /** @@ -42,8 +43,11 @@ public class EditProjectValidationsTest extends ZanataTestCase { @Rule public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - @Test - public void setValidationOptions() { + @Feature(summary = "The administrator can change the validation levels " + + "for a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void setValidationOptions() throws Exception { ProjectTranslationTab projectTranslationTab = new LoginWorkFlow() .signIn("admin", "admin") @@ -52,9 +56,10 @@ public void setValidationOptions() { .gotoSettingsTab() .gotoSettingsTranslationTab(); - assertThat("The level for tabs is currently Warning", - projectTranslationTab.isValidationLevel( - "Tab characters (\\t)", "Warning")); + assertThat(projectTranslationTab + .isValidationLevel("Tab characters (\\t)", "Warning")) + .isTrue() + .as("The level for tabs is currently Warning"); projectTranslationTab = projectTranslationTab .setValidationLevel("HTML/XML tags", "Error") @@ -73,48 +78,73 @@ public void setValidationOptions() { .gotoSettingsTab() .gotoSettingsTranslationTab(); - assertThat("The validation changes were saved", projectTranslationTab - .isValidationLevel("HTML/XML tags", "Error")); - assertThat("The validation changes were saved", projectTranslationTab - .isValidationLevel("Java variables", "Error")); - assertThat("The validation changes were saved", projectTranslationTab - .isValidationLevel("Leading/trailing newline (\\n)", "Error")); - assertThat("The validation changes were saved", projectTranslationTab - .isValidationLevel("Printf variables", "Error")); - assertThat("The validation changes were saved", projectTranslationTab - .isValidationLevel("Tab characters (\\t)", "Error")); - assertThat("The validation changes were saved", projectTranslationTab - .isValidationLevel("XML entity reference", "Error")); + assertThat(projectTranslationTab + .isValidationLevel("HTML/XML tags", "Error")) + .isTrue() + .as("The validation changes were saved"); + assertThat(projectTranslationTab + .isValidationLevel("Java variables", "Error")) + .isTrue() + .as("The validation changes were saved"); + assertThat(projectTranslationTab + .isValidationLevel("Leading/trailing newline (\\n)", "Error")) + .isTrue() + .as("The validation changes were saved"); + assertThat(projectTranslationTab + .isValidationLevel("Printf variables", "Error")) + .isTrue() + .as("The validation changes were saved"); + assertThat(projectTranslationTab + .isValidationLevel("Tab characters (\\t)", "Error")) + .isTrue() + .as("The validation changes were saved"); + assertThat(projectTranslationTab + .isValidationLevel("XML entity reference", "Error")) + .isTrue() + .as("The validation changes were saved"); } - @Test - public void printfAndPositionalPrintfAreExclusive() { + @Feature(summary = "The system will only allow one of the two Printf " + + "validation options to be active at one time", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void printfAndPositionalPrintfAreExclusive() throws Exception { ProjectTranslationTab projectTranslationTab = new LoginWorkFlow() - .signIn("admin", "admin") - .goToProjects() - .goToProject("about fedora") - .gotoSettingsTab() - .gotoSettingsTranslationTab() - .setValidationLevel( - "Positional printf (XSI extension)", "Error"); - - assertThat("The Positional printf level is Error", - projectTranslationTab.isValidationLevel( - "Positional printf (XSI extension)", "Error")); - - assertThat("The Printf level is Off", - projectTranslationTab - .isValidationLevel("Printf variables", "Off")); + .signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsTranslationTab() + .setValidationLevel( + "Positional printf (XSI extension)", "Error"); + + projectTranslationTab.expectNotification("Updated validation " + + "Positional printf (XSI extension) to Error."); + + assertThat(projectTranslationTab + .isValidationLevel("Positional printf (XSI extension)", "Error")) + .isTrue() + .as("The Positional printf level is Error"); + + assertThat(projectTranslationTab + .isValidationLevel("Printf variables", "Off")) + .isTrue() + .as("The Printf level is Off"); projectTranslationTab = projectTranslationTab .setValidationLevel("Printf variables", "Error"); - assertThat("The Printf level is Error", - projectTranslationTab - .isValidationLevel("Printf variables", "Error")); + projectTranslationTab.expectNotification("Updated validation " + + "Printf variables to Error."); + + assertThat(projectTranslationTab + .isValidationLevel("Printf variables", "Error")) + .isTrue() + .as("The Printf level is Error"); - assertThat("The Positional printf level is Off", - projectTranslationTab.isValidationLevel( - "Positional printf (XSI extension)", "Off")); + assertThat(projectTranslationTab + .isValidationLevel("Positional printf (XSI extension)", "Off")) + .isTrue() + .as("The Positional printf level is Off"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java b/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java index 0fea070941..af1c8a58c7 100644 --- a/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java +++ b/functional-test/src/test/java/org/zanata/feature/projectversion/CreateProjectVersionTest.java @@ -24,6 +24,7 @@ import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; import org.zanata.feature.testharness.TestPlan.DetailedTest; @@ -34,10 +35,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.not; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Damian Jansen enabledLocaleList = versionLanguagesTab .getEnabledLocaleList(); - assertThat("The enabled list contains three languages", - enabledLocaleList, - contains("French[fr]", "Hindi[hi]", "Polish[pl]")); + assertThat(enabledLocaleList) + .contains("French[fr]", "Hindi[hi]", "Polish[pl]") + .as("The enabled list contains three languages"); - assertThat("The enabled list does not contain " + - "'English (United States)[en-US]'", - enabledLocaleList, - not(hasItem("English (United States)[en-US]"))); + assertThat(enabledLocaleList) + .doesNotContain("English (United States)[en-US]") + .as("The enabled list does not contain " + + "'English (United States)[en-US]'"); versionLanguagesTab = versionLanguagesTab.removeLocale("pl"); versionLanguagesTab.waitForLanguagesNotContains( @@ -84,13 +85,10 @@ public void changeVersionLanguages() { versionLanguagesTab.waitForLanguagesNotContains("Polish[pl]"); enabledLocaleList = versionLanguagesTab.getEnabledLocaleList(); - assertThat("The enabled list does not contain 'US English'", - enabledLocaleList, - not(hasItem("English (United States)[en-US]"))); - - assertThat("The enabled list does not contain 'Polish'", - enabledLocaleList, - not(hasItem("Polish[pl]"))); + assertThat(enabledLocaleList) + .doesNotContain("English (United States)[en-US]") + .doesNotContain("Polish[pl]") + .as("The enabled list does not contain 'US English' or Polish"); versionLanguagesTab = versionLanguagesTab .gotoSettingsTab() @@ -102,10 +100,10 @@ public void changeVersionLanguages() { "English (United States)[en-US]"); enabledLocaleList = versionLanguagesTab.getEnabledLocaleList(); - assertThat("Three languages are available to translate", - enabledLocaleList, - contains("English (United States)[en-US]", + assertThat(enabledLocaleList) + .contains("English (United States)[en-US]", "French[fr]", - "Hindi[hi]")); + "Hindi[hi]") + .as("Three languages are available to translate"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/projectversion/EditVersionValidationsTest.java b/functional-test/src/test/java/org/zanata/feature/projectversion/EditVersionValidationsTest.java index d915103d5f..a1798b1278 100644 --- a/functional-test/src/test/java/org/zanata/feature/projectversion/EditVersionValidationsTest.java +++ b/functional-test/src/test/java/org/zanata/feature/projectversion/EditVersionValidationsTest.java @@ -20,10 +20,10 @@ */ package org.zanata.feature.projectversion; -import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.projectversion.versionsettings.VersionTranslationTab; @@ -32,8 +32,7 @@ import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; /** @@ -46,8 +45,11 @@ public class EditVersionValidationsTest extends ZanataTestCase { @Rule public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - @Test - public void setValidationOptions() { + @Feature(summary = "The administrator can set validation options for " + + "a project version", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void setValidationOptions() throws Exception { VersionTranslationTab versionTranslationTab = new LoginWorkFlow() .signIn("admin", "admin") .goToProjects() @@ -56,8 +58,10 @@ public void setValidationOptions() { .gotoSettingsTab() .gotoSettingsTranslationTab(); - assertThat("The level is currently Warning", versionTranslationTab - .isValidationLevel("Tab characters (\\t)", "Warning")); + assertThat(versionTranslationTab + .isValidationLevel("Tab characters (\\t)", "Warning")) + .isTrue() + .as("The level is currently Warning"); versionTranslationTab = versionTranslationTab .setValidationLevel("Tab characters (\\t)", "Error"); @@ -72,13 +76,16 @@ public void setValidationOptions() { .gotoSettingsTab() .gotoSettingsTranslationTab(); - assertThat("The changes were saved", versionTranslationTab - .isValidationLevel("Tab characters (\\t)", "Error")); + assertThat(versionTranslationTab + .isValidationLevel("Tab characters (\\t)", "Error")) + .as("The changes were saved"); } - - @Test - public void verifyValidationsAreErrors() { + @Feature(summary = "The system recognises validation errors options in " + + "translation targets and displays them to the user", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void verifyValidationsAreErrors() throws Exception { VersionTranslationTab versionTranslationTab = new LoginWorkFlow() .signIn("admin", "admin") .goToProjects() @@ -93,36 +100,31 @@ public void verifyValidationsAreErrors() { EditorPage editorPage = new ProjectWorkFlow() .goToProjectByName("about fedora") .gotoVersion("master") - .translate("fr", "About_Fedora") - .setSyntaxHighlighting(false); - - assertThat("The text in the translation target is blank", - editorPage.getBasicTranslationTargetAtRowIndex(0), - equalTo("")); - - editorPage.pasteIntoRowAtIndex(0, "\t"); + .translate("fr", "About_Fedora"); - assertThat("The text in the translation target is now a tab", - editorPage.getBasicTranslationTargetAtRowIndex(0), - equalTo("\t")); + assertThat(editorPage.getBasicTranslationTargetAtRowIndex(0)) + .isEqualTo("") + .as("The text in the translation target is blank"); - editorPage.defocus(); + editorPage.pasteIntoRowAtIndex(0, "\t").saveAsFuzzyAtRow(0); editorPage.waitForValidationErrorsVisible(); - assertThat("The notification area shows there's an error", - editorPage.getValidationMessageCurrentTarget(), - equalTo("Warning: none, Errors: 1")); + assertThat(editorPage.getValidationMessageCurrentTarget()) + .isEqualTo("Warning: none, Errors: 1") + .as("The notification area shows there's an error"); editorPage = editorPage.openValidationBox(); - assertThat("The correct error is shown for the validation", - editorPage.getValidationMessageCurrentTarget(), - Matchers.containsString("Target has more tabs (\\t) than source " - + "(source: 0, target: 1)")); + assertThat(editorPage.getValidationMessageCurrentTarget()) + .contains("Target has more tabs (\\t) than source " + + "(source: 0, target: 1)") + .as("The correct error is shown for the validation"); } - @Test - public void userCannotTurnOffEnforcedValidations() { + @Feature(summary = "The user cannot disable enforced validations", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void userCannotTurnOffEnforcedValidations() throws Exception { VersionTranslationTab versionTranslationTab = new LoginWorkFlow() .signIn("admin", "admin") .goToProjects() @@ -140,17 +142,22 @@ public void userCannotTurnOffEnforcedValidations() { .translate("fr", "About_Fedora") .openValidationOptions(); - assertThat("The option is selected", - editorPage.isValidationOptionSelected( - EditorPage.Validations.TABS)); + assertThat(editorPage.isValidationOptionSelected( + EditorPage.Validations.TABS)) + .isTrue() + .as("The option is selected"); - assertThat("The option is unavailable", - !editorPage.isValidationOptionAvailable( - EditorPage.Validations.TABS)); + assertThat(editorPage.isValidationOptionAvailable( + EditorPage.Validations.TABS)) + .isFalse() + .as("The option is unavailable"); } - @Test - public void printfAndPositionalPrintfAreExclusive() { + @Feature(summary = "The user cannot select both printf formats for " + + "validation options", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void printfAndPositionalPrintfAreExclusive() throws Exception { VersionTranslationTab versionTranslationTab = new LoginWorkFlow() .signIn("admin", "admin") .goToProjects() @@ -160,24 +167,36 @@ public void printfAndPositionalPrintfAreExclusive() { .gotoSettingsTranslationTab() .setValidationLevel( "Positional printf (XSI extension)", "Error"); - - assertThat("The Positional printf level is Error", - versionTranslationTab.isValidationLevel( - "Positional printf (XSI extension)", "Error")); - assertThat("The Printf level is Off", - versionTranslationTab.isValidationLevel("Printf variables", "Off")); + versionTranslationTab.expectNotification( + "Updated validation Positional printf (XSI extension) to Error."); + + assertThat(versionTranslationTab + .isValidationLevel("Positional printf (XSI extension)", "Error")) + .isTrue() + .as("The Positional printf level is Error"); + assertThat(versionTranslationTab + .isValidationLevel("Printf variables", "Off")) + .isTrue() + .as("The Printf level is Off"); versionTranslationTab.setValidationLevel("Printf variables", "Error"); - - assertThat("The Printf level is Error", - versionTranslationTab.isValidationLevel("Printf variables", "Error")); - assertThat("The Positional printf level is Off", - versionTranslationTab.isValidationLevel( - "Positional printf (XSI extension)", "Off")); + versionTranslationTab.expectNotification( + "Updated validation Printf variables to Error."); + + assertThat(versionTranslationTab + .isValidationLevel("Printf variables", "Error")) + .isTrue() + .as("The Printf level is Error"); + assertThat(versionTranslationTab + .isValidationLevel("Positional printf (XSI extension)", "Off")) + .isTrue() + .as("The Positional printf level is Off"); } - @Test - public void userCanEnableADisabledValidation() { + @Feature(summary = "The user can turn on a disabled validation option", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void userCanEnableADisabledValidation() throws Exception { VersionTranslationTab versionTranslationTab = new LoginWorkFlow() .signIn("admin", "admin") .goToProjects() @@ -193,20 +212,21 @@ public void userCanEnableADisabledValidation() { .goToProjectByName("about fedora") .gotoVersion("master") .translate("fr", "About_Fedora") - .setSyntaxHighlighting(false) - .pasteIntoRowAtIndex(0, "\t"); + .pasteIntoRowAtIndex(0, "\t") + .saveAsFuzzyAtRow(0); - assertThat("The validation errors are not shown", - !editorPage.isValidationMessageCurrentTargetVisible()); + assertThat(editorPage.isValidationMessageCurrentTargetVisible()) + .isFalse() + .as("The validation errors are not shown"); editorPage = editorPage .openValidationOptions() .clickValidationCheckbox(EditorPage.Validations.TABS); - editorPage.waitForValidationErrorsVisible(); - assertThat("The validation errors are shown", - editorPage.isValidationMessageCurrentTargetVisible()); + assertThat(editorPage.isValidationMessageCurrentTargetVisible()) + .isTrue() + .as("The validation errors are shown"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/projectversion/VersionFilteringTest.java b/functional-test/src/test/java/org/zanata/feature/projectversion/VersionFilteringTest.java index fc947e2e39..e99e17a30d 100644 --- a/functional-test/src/test/java/org/zanata/feature/projectversion/VersionFilteringTest.java +++ b/functional-test/src/test/java/org/zanata/feature/projectversion/VersionFilteringTest.java @@ -23,15 +23,14 @@ import org.junit.ClassRule; import org.junit.Test; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.page.projects.ProjectVersionsPage; import org.zanata.util.SampleProjectRule; import org.zanata.workflow.LoginWorkFlow; import org.zanata.workflow.ProjectWorkFlow; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Damian Jansen @@ -42,106 +41,84 @@ public class VersionFilteringTest extends ZanataTestCase { @ClassRule public static SampleProjectRule sampleProjectRule = new SampleProjectRule(); - @Test - public void versionSearchFiltering() { - + @Feature(summary = "The user can filter project versions by name", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void versionSearchFiltering() throws Exception { String projectName = "versionsearchnums"; - assertThat("Login as translator", - new LoginWorkFlow().signIn("translator", "translator") - .loggedInAs(), - equalTo("translator")); - - assertThat("The project is created", - new ProjectWorkFlow() - .createNewSimpleProject("version-search", projectName) - .getProjectName(), - equalTo(projectName)); - - assertThat("The version alpha is created", - new ProjectWorkFlow() - .createNewProjectVersion(projectName, "alpha") - .getProjectVersionName(), - equalTo("alpha")); - - assertThat("The version bravo is created", - new ProjectWorkFlow() - .createNewProjectVersion(projectName, "bravo") - .getProjectVersionName(), - equalTo("bravo")); + assertThat(new LoginWorkFlow() + .signIn("translator", "translator") + .loggedInAs()) + .isEqualTo("translator") + .as("Login as translator"); + + assertThat(new ProjectWorkFlow() + .createNewSimpleProject("version-search", projectName) + .getProjectName()) + .isEqualTo(projectName) + .as("The project is created"); + + assertThat(new ProjectWorkFlow() + .createNewProjectVersion(projectName, "alpha") + .getProjectVersionName()) + .isEqualTo("alpha") + .as("The version alpha is created"); + + assertThat(new ProjectWorkFlow() + .createNewProjectVersion(projectName, "bravo") + .getProjectVersionName()) + .isEqualTo("bravo") + .as("The version bravo is created"); ProjectVersionsPage projectVersionsPage = new ProjectWorkFlow() .goToProjectByName(projectName) .waitForDisplayedVersions(2); - assertThat("The version count is 2", - projectVersionsPage.getNumberOfDisplayedVersions(), - equalTo(2)); - - assertThat("The versions are correct", - projectVersionsPage.getVersions(), - contains("bravo", "alpha")); + assertVersions(projectVersionsPage, 2, new String[]{"bravo", "alpha"}); projectVersionsPage = projectVersionsPage .clickSearchIcon() .enterVersionSearch("alpha") .waitForDisplayedVersions(1); - assertThat("The version count is 1", - projectVersionsPage.getNumberOfDisplayedVersions(), - equalTo(1)); - - assertThat("The versions are correct", - projectVersionsPage.getVersions(), - contains("alpha")); + assertVersions(projectVersionsPage, 1, new String[]{"alpha"}); projectVersionsPage = projectVersionsPage .clearVersionSearch() .waitForDisplayedVersions(2); - assertThat("The version count is 2 again", - projectVersionsPage.getNumberOfDisplayedVersions(), - equalTo(2)); - - assertThat("The versions are correct", - projectVersionsPage.getVersions(), - contains("bravo", "alpha")); + assertVersions(projectVersionsPage, 2, new String[]{"bravo", "alpha"}); projectVersionsPage = projectVersionsPage .enterVersionSearch("bravo") .waitForDisplayedVersions(1); - assertThat("The version count is 1", - projectVersionsPage.getNumberOfDisplayedVersions(), - equalTo(1)); - - assertThat("The versions are correct", - projectVersionsPage.getVersions(), - contains("bravo")); + assertVersions(projectVersionsPage, 1, new String[]{"bravo"}); projectVersionsPage = projectVersionsPage .clearVersionSearch() .enterVersionSearch("charlie") .waitForDisplayedVersions(0); - assertThat("The version count is 0", - projectVersionsPage.getNumberOfDisplayedVersions(), - equalTo(0)); - - assertThat("The versions are correct", - projectVersionsPage.getVersions().size(), - equalTo(0)); + assertVersions(projectVersionsPage, 0, new String[]{}); projectVersionsPage = projectVersionsPage .clearVersionSearch() .waitForDisplayedVersions(2); - assertThat("The version count is 2 again", - projectVersionsPage.getNumberOfDisplayedVersions(), - equalTo(2)); + assertVersions(projectVersionsPage, 2, new String[]{"bravo", "alpha"}); + } + + private void assertVersions(ProjectVersionsPage page, + int versionsCount, + String[] versionNames) { + assertThat(page.getNumberOfDisplayedVersions()) + .isEqualTo(versionsCount) + .as("The version count is " + versionsCount); - assertThat("The versions are correct", - projectVersionsPage.getVersions(), - contains("bravo", "alpha")); + assertThat(page.getVersions()) + .contains(versionNames) + .as("The versions are correct"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/search/ProjectSearchTest.java b/functional-test/src/test/java/org/zanata/feature/search/ProjectSearchTest.java index dcecd5034e..5be1855567 100644 --- a/functional-test/src/test/java/org/zanata/feature/search/ProjectSearchTest.java +++ b/functional-test/src/test/java/org/zanata/feature/search/ProjectSearchTest.java @@ -21,14 +21,12 @@ package org.zanata.feature.search; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.not; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; import org.zanata.page.BasePage; @@ -48,52 +46,63 @@ public class ProjectSearchTest extends ZanataTestCase { @Rule public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - @Test - public void successfulProjectSearchAndDisplay() { + @Feature(summary = "The user can search for a project", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void successfulProjectSearchAndDisplay() throws Exception { BasePage basePage = new BasicWorkFlow() .goToHome() .enterSearch("about") .waitForSearchListContains("about fedora"); - assertThat("Normal user can see the project", - basePage.getProjectSearchAutocompleteItems(), - hasItem("about fedora")); + assertThat(basePage.getProjectSearchAutocompleteItems()) + .contains("about fedora") + .as("Normal user can see the project"); ProjectBasePage projectPage = basePage.clickSearchEntry("about fedora"); - assertThat("The project page is the correct one", projectPage - .getProjectName().trim(), // UI adds a space - equalTo("about fedora")); + assertThat(projectPage.getProjectName().trim()) + .isEqualTo("about fedora") + .as("The project page is the correct one"); } - @Test - public void unsuccessfulProjectSearch() { + @Feature(summary = "The system will provide no results on an " + + "unsuccessful search", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void unsuccessfulProjectSearch() throws Exception { ProjectsPage projectsPage = new BasicWorkFlow() .goToHome() .enterSearch("arodef") .waitForSearchListContains("Search Zanata for 'arodef'") .submitSearch(); - assertThat("No projects are displayed", projectsPage - .getProjectNamesOnCurrentPage().isEmpty()); + assertThat(projectsPage.getProjectNamesOnCurrentPage().isEmpty()) + .isTrue() + .as("No projects are displayed"); } - @Test - public void normalUserCannotSearchObsolete() { - new LoginWorkFlow().signIn("admin", "admin").goToProjects() - .goToProject("about fedora").gotoSettingsTab() - .gotoSettingsGeneral().archiveProject().logout(); + @Feature(summary = "The user cannot search for Obsolete projects", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void normalUserCannotSearchObsolete() throws Exception { + new LoginWorkFlow().signIn("admin", "admin") + .goToProjects() + .goToProject("about fedora") + .gotoSettingsTab() + .gotoSettingsGeneral() + .archiveProject() + .logout(); BasePage basePage = new BasicWorkFlow() .goToHome() .enterSearch("about") .waitForSearchListContains("Search Zanata for 'about'"); - assertThat("User cannot see the obsolete project", - basePage.getProjectSearchAutocompleteItems(), - not(hasItem("About Fedora"))); - + assertThat(basePage.getProjectSearchAutocompleteItems()) + .doesNotContain("About Fedora") + .as("User cannot see the obsolete project"); } } diff --git a/functional-test/src/test/java/org/zanata/feature/security/SecurityFullTest.java b/functional-test/src/test/java/org/zanata/feature/security/SecurityFullTest.java deleted file mode 100644 index 67f781fa28..0000000000 --- a/functional-test/src/test/java/org/zanata/feature/security/SecurityFullTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2013, Red Hat, Inc. and individual contributors as indicated by the - * @author tags. See the copyright.txt file in the distribution for a full - * listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this software; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF - * site: http://www.fsf.org. - */ -package org.zanata.feature.security; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.zanata.feature.testharness.ZanataTestCase; -import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; -import org.zanata.feature.testharness.TestPlan.DetailedTest; -import org.zanata.page.account.ResetPasswordPage; -import org.zanata.page.account.SignInPage; -import org.zanata.page.dashboard.DashboardBasePage; -import org.zanata.util.AddUsersRule; -import org.zanata.workflow.BasicWorkFlow; -import org.zanata.workflow.LoginWorkFlow; - -/** - * @author Damian Jansen djansen@redhat.com - */ -@Category(DetailedTest.class) -public class SecurityFullTest extends ZanataTestCase { - - @Rule - public AddUsersRule addUsersRule = new AddUsersRule(); - - @Before - public void before() { - // Remove all cookies, no previous login is allowed - new BasicWorkFlow().goToHome().deleteCookiesAndRefresh(); - } - - @Test - @Category(BasicAcceptanceTest.class) - public void signInSuccessful() { - DashboardBasePage dashboardPage = - new LoginWorkFlow().signIn("admin", "admin"); - assertThat("User is logged in", dashboardPage.loggedInAs(), - equalTo("admin")); - } - - @Test - @Category(BasicAcceptanceTest.class) - public void signInFailure() { - SignInPage signInPage = new LoginWorkFlow() - .signInFailure("nosuchuser", "password"); - - assertThat("Error message is shown", - signInPage.waitForFieldErrors(), - Matchers.hasItem("Login failed")); - } - - @Test - @Ignore("RHBZ-987707 | Cannot intercept email yet") - public void resetPasswordSuccessful() { - SignInPage signInPage = - new BasicWorkFlow().goToHome().clickSignInLink(); - ResetPasswordPage resetPasswordPage = signInPage.goToResetPassword(); - resetPasswordPage = - resetPasswordPage.enterUserName("nosuchuser").enterEmail( - "nosuchuser@nosuchdomain.com"); - resetPasswordPage = resetPasswordPage.resetPassword(); - // TODO: Reset Success page - } - - @Test - public void resetPasswordFailureForInvalidAccount() { - SignInPage signInPage = - new BasicWorkFlow().goToHome().clickSignInLink(); - ResetPasswordPage resetPasswordPage = signInPage.goToResetPassword(); - resetPasswordPage = - resetPasswordPage.enterUserName("nosuchuser").enterEmail( - "nosuchuser@nosuchdomain.com"); - resetPasswordPage = resetPasswordPage.resetFailure(); - assertThat("A no such account message is displayed", - resetPasswordPage.getNotificationMessage(), - equalTo("No such account found")); - } - - @Test - public void invalidResetPasswordFieldEntries() { - SignInPage signInPage = - new BasicWorkFlow().goToHome().clickSignInLink(); - ResetPasswordPage resetPasswordPage = signInPage.goToResetPassword(); - resetPasswordPage = - resetPasswordPage.enterUserName("b").enterEmail("b"); - resetPasswordPage = resetPasswordPage.resetFailure(); - - assertThat("Invalid email error is displayed", - resetPasswordPage.waitForErrors(), - hasItem("not a well-formed email address")); - - // Both are valid, but show seemingly at random - assertThat( - resetPasswordPage.getErrors().get(0), - either(equalTo("size must be between 3 and 20")).or( - equalTo("must match ^[a-z\\d_]{3,20}$"))); - - } - - @Test - public void emptyResetPasswordFieldEntries() { - SignInPage signInPage = - new BasicWorkFlow().goToHome().clickSignInLink(); - ResetPasswordPage resetPasswordPage = signInPage.goToResetPassword(); - resetPasswordPage = resetPasswordPage.clearFields(); - resetPasswordPage = resetPasswordPage.resetFailure(); - - assertThat("Empty email error is displayed", - resetPasswordPage.waitForErrors(), hasItem("may not be empty")); - - // All are valid, but may show at random - assertThat( - resetPasswordPage.getErrors().get(0), - either(equalTo("size must be between 3 and 20")).or( - equalTo("may not be empty")).or( - equalTo("must match ^[a-z\\d_]{3,20}$"))); - - } - -} diff --git a/functional-test/src/test/java/org/zanata/feature/security/SecurityTest.java b/functional-test/src/test/java/org/zanata/feature/security/SecurityTest.java new file mode 100644 index 0000000000..d00cbe34cb --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/security/SecurityTest.java @@ -0,0 +1,178 @@ +/* + * Copyright 2013, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.feature.security; + +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.subethamail.wiser.WiserMessage; +import org.zanata.feature.Feature; +import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; +import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.page.account.ResetPasswordPage; +import org.zanata.util.AddUsersRule; +import org.zanata.util.EnsureLogoutRule; +import org.zanata.util.HasEmailRule; +import org.zanata.util.RetryRule; +import org.zanata.workflow.BasicWorkFlow; +import org.zanata.workflow.LoginWorkFlow; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Damian Jansen djansen@redhat.com + */ +@Category(DetailedTest.class) +public class SecurityTest extends ZanataTestCase { + + @Rule + public HasEmailRule hasEmailRule = new HasEmailRule(); + + @Rule + public EnsureLogoutRule ensureLogoutRule = new EnsureLogoutRule(); + + @Rule + public AddUsersRule addUsersRule = new AddUsersRule(); + + @Feature(summary = "The user can log in", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86815) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + @Category(BasicAcceptanceTest.class) + public void signInSuccessful() { + assertThat(new LoginWorkFlow() + .signIn("admin", "admin") + .loggedInAs()) + .isEqualTo("admin") + .as("User can log in"); + } + + @Feature(summary = "The user must enter a correct username and " + + "password to log in", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 86815) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + @Category(BasicAcceptanceTest.class) + public void signInFailure() { + assertThat(new LoginWorkFlow() + .signInFailure("nosuchuser", "password") + .waitForFieldErrors()) + .contains("Login failed") + .as("Log in error message is shown"); + } + + @Feature(summary = "The user may reset their password via email", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void resetPasswordSuccessful() { + ResetPasswordPage resetPasswordPage = new BasicWorkFlow() + .goToHome() + .clickSignInLink() + .goToResetPassword() + .enterUserName("admin") + .enterEmail("admin@example.com") + .resetPassword(); + + assertThat(resetPasswordPage.getNotificationMessage()) + .isEqualTo("You will soon receive an email with a link to " + + "reset your password."); + + WiserMessage message = hasEmailRule.getMessages().get(0); + String emailContent = HasEmailRule.getEmailContent(message); + + assertThat(message.getEnvelopeReceiver()) + .isEqualTo("admin@example.com") + .as("Zanata has sent an email to the user"); + assertThat(emailContent) + .contains("Please follow the link below to reset the " + + "password for your account.") + .as("The system has sent a reset password email to the user"); + } + + @Feature(summary = "The user must enter a known account and email pair " + + "to reset their password", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void resetPasswordFailureForInvalidAccount() { + ResetPasswordPage resetPasswordPage = new BasicWorkFlow() + .goToHome() + .clickSignInLink() + .goToResetPassword() + .enterUserName("nosuchuser") + .enterEmail("nosuchuser@nosuchdomain.com") + .resetFailure(); + + assertThat(resetPasswordPage.getNotificationMessage()) + .isEqualTo("No such account found") + .as("A no such account message is displayed"); + } + + @Feature(summary = "The user must enter a valid account and email pair " + + "to reset their password", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void invalidResetPasswordFieldEntries() { + ResetPasswordPage resetPasswordPage = new BasicWorkFlow() + .goToHome() + .clickSignInLink() + .goToResetPassword() + .enterUserName("b") + .enterEmail("b") + .resetFailure(); + + assertThat(resetPasswordPage.waitForErrors()) + .contains("not a well-formed email address") + .as("Invalid email error is displayed"); + + String error = resetPasswordPage.getErrors().get(0); + // Both are valid, but show seemingly at random + assertThat(error.equals("size must be between 3 and 20") || + error.equals("must match ^[a-z\\d_]{3,20}$")) + .isTrue() + .as("Invalid email error is displayed"); + } + + @Feature(summary = "The user must enter both an account name and email " + + "address to reset their password", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 0) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void emptyResetPasswordFieldEntries() { + ResetPasswordPage resetPasswordPage = new BasicWorkFlow() + .goToHome() + .clickSignInLink() + .goToResetPassword() + .clearFields() + .resetFailure(); + + assertThat(resetPasswordPage.waitForErrors()) + .contains("may not be empty") + .as("Empty email error is displayed"); + + // All are valid, but may show at random + String error = resetPasswordPage.getErrors().get(0); + assertThat(error.equals("size must be between 3 and 20") || + error.equals("may not be empty") || + error.equals("must match ^[a-z\\d_]{3,20}$")) + .as("The regex match for the reset password field has failed"); + } + +} diff --git a/functional-test/src/test/java/org/zanata/feature/testharness/TestPlan.java b/functional-test/src/test/java/org/zanata/feature/testharness/TestPlan.java index 21c53d1ff0..f382958770 100644 --- a/functional-test/src/test/java/org/zanata/feature/testharness/TestPlan.java +++ b/functional-test/src/test/java/org/zanata/feature/testharness/TestPlan.java @@ -37,7 +37,7 @@ import org.zanata.feature.project.*; import org.zanata.feature.projectversion.*; import org.zanata.feature.search.ProjectSearchTest; -import org.zanata.feature.security.SecurityFullTest; +import org.zanata.feature.security.SecurityTest; import org.zanata.feature.versionGroup.*; /** @@ -72,11 +72,12 @@ * The actions of an administrator, such as editing users and * translation memory sets */ + AutoRoleAssignmentTest.class, EditHomePageTest.class, EditTranslationMemoryTest.class, EditTranslationMemoryTest.class, ManageSearchTest.class, - ManageUsersFullTest.class, + ManageUsersTest.class, /* Client-Server * Usage of the mvn client @@ -166,13 +167,13 @@ * Security * Login/logout and access rights */ - SecurityFullTest.class, + SecurityTest.class, /* * Version Groups * Creation and management of Version Groups */ - VersionGroupFullTest.class, + VersionGroupTest.class, VersionGroupIDValidationTest.class, VersionGroupUrlTest.class }) diff --git a/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java b/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java index 59060d8613..1044ef01a3 100644 --- a/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java +++ b/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java @@ -30,7 +30,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestName; -import org.junit.rules.Timeout; import org.zanata.util.RetryRule; /** @@ -42,8 +41,8 @@ @Slf4j public class ZanataTestCase { - /* Maximum five minute test duration */ - private static int MAX_TEST_DURATION = 300000; + public final static int MAX_SHORT_TEST_DURATION = 120000; + public final static int MAX_LONG_TEST_DURATION = 300000; @Rule public RetryRule retryRule = new RetryRule(1); diff --git a/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupFullTest.java b/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupFullTest.java deleted file mode 100644 index 98a1995391..0000000000 --- a/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupFullTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2013, Red Hat, Inc. and individual contributors as indicated by the - * @author tags. See the copyright.txt file in the distribution for a full - * listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this software; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF - * site: http://www.fsf.org. - */ -package org.zanata.feature.versionGroup; - -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.zanata.feature.testharness.ZanataTestCase; -import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; -import org.zanata.feature.testharness.TestPlan.DetailedTest; -import org.zanata.page.dashboard.DashboardBasePage; -import org.zanata.page.groups.CreateVersionGroupPage; -import org.zanata.page.groups.VersionGroupPage; -import org.zanata.page.groups.VersionGroupsPage; -import org.zanata.util.SampleProjectRule; -import org.zanata.workflow.LoginWorkFlow; - -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * @author Damian Jansen djansen@redhat.com - */ -@Category(DetailedTest.class) -public class VersionGroupFullTest extends ZanataTestCase { - - @Rule - public SampleProjectRule sampleProjectRule = new SampleProjectRule(); - private DashboardBasePage dashboardPage; - - @Before - public void before() { - dashboardPage = new LoginWorkFlow().signIn("admin", "admin"); - } - - @Test - @Category(BasicAcceptanceTest.class) - public void createABasicGroup() { - String groupID = "basic-group"; - String groupName = "A Basic Group"; - - CreateVersionGroupPage createVersionGroupPage = - dashboardPage.goToGroups().createNewGroup(); - createVersionGroupPage.inputGroupId(groupID); - createVersionGroupPage.inputGroupName(groupName); - createVersionGroupPage - .inputGroupDescription("A basic group can be saved"); - VersionGroupsPage versionGroupsPage = - createVersionGroupPage.saveGroup(); - assertThat("Group was created", versionGroupsPage.getGroupNames() - .contains(groupName)); - VersionGroupPage groupView = versionGroupsPage.goToGroup(groupName); - assertThat("The group is displayed", groupView.getTitle(), - Matchers.equalTo("Groups - ".concat(groupName))); - } - - @Test - public void requiredFields() { - String errorMsg = "value is required"; - String groupID = "verifyRequiredFieldsGroupID"; - String groupName = "verifyRequiredFieldsGroupName"; - - CreateVersionGroupPage groupPage = - dashboardPage.goToGroups().createNewGroup().saveGroupFailure(); - assertThat("The two errors are value is required", - groupPage.getFieldValidationErrors(), Matchers.contains(errorMsg, errorMsg)); - - groupPage = - groupPage.clearFields().inputGroupName(groupName) - .saveGroupFailure(); - assertThat("The value required error shown", groupPage.getFieldValidationErrors(), - Matchers.contains(errorMsg)); - - groupPage = - groupPage.clearFields().inputGroupId(groupID) - .saveGroupFailure(); - assertThat("The value required error shown", groupPage.getFieldValidationErrors(), - Matchers.contains(errorMsg)); - } - - @Test - public void groupIDFieldSize() { - String groupID = "abcdefghijklmnopqrstuvwxyzabcdefghijklmn"; - String groupIDExtra = "xyz"; - String groupName = "verifyIDFieldSizeName"; - - CreateVersionGroupPage groupPage = dashboardPage - .goToGroups() - .createNewGroup() - .inputGroupId(groupID + groupIDExtra) - .inputGroupName(groupName) - .saveGroupFailure(); - - assertThat("User cannot enter more than 40 characters", - groupPage.getGroupIdValue(), - Matchers.equalTo(groupID)); - } - - @Test - public void groupDescriptionFieldSize() { - String errorMsg = "value must be shorter than or equal to 100 characters"; - String groupID = "verifyDescriptionFieldSizeID"; - String groupName = "verifyDescriptionFieldSizeName"; - String groupDescription = - "This text is to test that the description field takes no more than exactly 100 characters - actually."; - - assertThat("Description length is greater than 100 characters", - groupDescription.length(), Matchers.equalTo(101)); - CreateVersionGroupPage groupPage = - dashboardPage.goToGroups().createNewGroup(); - groupPage.inputGroupId(groupID).inputGroupName(groupName) - .inputGroupDescription(groupDescription); - groupPage.saveGroupFailure(); - assertThat("Invalid length error is shown", - groupPage.getFieldValidationErrors(), - Matchers.contains(errorMsg)); - - groupPage.clearFields(); - groupDescription = groupDescription.substring(0, 100); - assertThat("Description length is now 100 characters", - groupDescription.length(), Matchers.equalTo(100)); - groupPage.inputGroupId("verifyDescriptionFieldSizeID").inputGroupName( - groupName); - VersionGroupsPage verGroupsPage = - groupPage.inputGroupDescription(groupDescription).saveGroup(); - assertThat("A group description of 100 chars is valid", - verGroupsPage.getGroupNames(), Matchers.hasItem(groupName)); - - } - - @Test - public void addANewProjectVersionToAnEmptyGroup() - throws InterruptedException { - String groupID = "add-version-to-empty-group"; - String groupName = "AddVersionToEmptyGroup"; - VersionGroupPage versionGroupPage = dashboardPage - .goToGroups() - .createNewGroup() - .inputGroupId(groupID) - .inputGroupName(groupName) - .saveGroup() - .goToGroup(groupName) - .clickProjectsTab() - .clickAddProjectVersionsButton(); - - versionGroupPage = versionGroupPage - .enterProjectVersion("about-fedora") - .selectProjectVersion("about-fedora master") - .clickProjectsTab(); - - assertThat("The version group shows in the list", - versionGroupPage.getProjectVersionsInGroup(), - Matchers.hasItem("about fedora\nmaster")); - - } - -} diff --git a/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupIDValidationTest.java b/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupIDValidationTest.java index cb7b92ecdc..f16ea66bb0 100644 --- a/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupIDValidationTest.java +++ b/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupIDValidationTest.java @@ -20,15 +20,15 @@ */ package org.zanata.feature.versionGroup; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.experimental.categories.Category; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; +import org.junit.rules.Timeout; import org.junit.runner.RunWith; import org.zanata.feature.testharness.ZanataTestCase; import org.zanata.feature.testharness.TestPlan.DetailedTest; @@ -44,6 +44,9 @@ @Category(DetailedTest.class) public class VersionGroupIDValidationTest extends ZanataTestCase { + @Rule + public Timeout timeout = new Timeout(ZanataTestCase.MAX_LONG_TEST_DURATION); + @Rule public AddUsersRule addUsersRule = new AddUsersRule(); @@ -107,10 +110,6 @@ public void goToGroupPage() { @Theory public void inputValidationForID(String inputText) { - String errorMsg = - "must start and end with letter or number, and " - + "contain only letters, numbers, underscores and hyphens."; - // Yes reassign groupPage is necessary since JSF re-renders itself after // each field input and selenium is not happy with it groupPage = groupPage @@ -119,7 +118,8 @@ public void inputValidationForID(String inputText) { .inputGroupName(inputText) .saveGroupFailure(); - assertThat("Validation error is displayed for input:" + inputText, - groupPage.getFieldErrors(), Matchers.hasItem(errorMsg)); + assertThat(groupPage.getFieldErrors()) + .contains(CreateVersionGroupPage.VALIDATION_ERROR) + .as("Validation error is displayed for input:" + inputText); } } diff --git a/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupTest.java b/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupTest.java new file mode 100644 index 0000000000..579ae4a1e4 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupTest.java @@ -0,0 +1,197 @@ +/* + * Copyright 2013, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.feature.versionGroup; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.zanata.feature.Feature; +import org.zanata.feature.testharness.ZanataTestCase; +import org.zanata.feature.testharness.TestPlan.BasicAcceptanceTest; +import org.zanata.feature.testharness.TestPlan.DetailedTest; +import org.zanata.page.dashboard.DashboardBasePage; +import org.zanata.page.groups.CreateVersionGroupPage; +import org.zanata.page.groups.VersionGroupPage; +import org.zanata.page.groups.VersionGroupsPage; +import org.zanata.util.SampleProjectRule; +import org.zanata.workflow.LoginWorkFlow; +import static org.zanata.util.FunctionalTestHelper.assumeTrue; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Damian Jansen djansen@redhat.com + */ +@Category(DetailedTest.class) +public class VersionGroupTest extends ZanataTestCase { + + @Rule + public SampleProjectRule sampleProjectRule = new SampleProjectRule(); + private DashboardBasePage dashboardPage; + + @Before + public void before() { + dashboardPage = new LoginWorkFlow().signIn("admin", "admin"); + } + + @Feature(summary = "The administrator can create a basic group", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 170109) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + @Category(BasicAcceptanceTest.class) + public void createABasicGroup() throws Exception { + String groupID = "basic-group"; + String groupName = "A Basic Group"; + VersionGroupsPage versionGroupsPage = dashboardPage + .goToGroups() + .createNewGroup() + .inputGroupId(groupID) + .inputGroupName(groupName) + .inputGroupDescription("A basic group can be saved") + .saveGroup(); + assertThat(versionGroupsPage.getGroupNames()) + .contains(groupName) + .as("The version group was created"); + VersionGroupPage groupView = versionGroupsPage.goToGroup(groupName); + assertThat(groupView.getTitle()) + .isEqualTo("Groups - ".concat(groupName)) + .as("The group is displayed"); + } + + @Feature(summary = "The administrator must fill in the required fields " + + "to create a group", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 170109) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void requiredFields() throws Exception { + String errorMsg = "value is required"; + String groupID = "verifyRequiredFieldsGroupID"; + String groupName = "verifyRequiredFieldsGroupName"; + + CreateVersionGroupPage groupPage = dashboardPage + .goToGroups() + .createNewGroup() + .saveGroupFailure(); + + assertThat(groupPage.getFieldValidationErrors()) + .contains(errorMsg, errorMsg) + .as("The two errors are value is required"); + + groupPage = groupPage.clearFields() + .inputGroupName(groupName) + .saveGroupFailure(); + + assertThat(groupPage.getFieldValidationErrors()) + .contains(errorMsg) + .as("The value required error shown"); + + groupPage = groupPage.clearFields() + .inputGroupId(groupID) + .saveGroupFailure(); + + assertThat(groupPage.getFieldValidationErrors()) + .contains(errorMsg) + .as("The value required error shown"); + } + + @Feature(summary = "The administrator must enter valid data into the " + + "required fields to create a group", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 170109) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void groupDescriptionFieldSize() throws Exception { + String groupID = "verifyDescriptionFieldSizeID"; + String groupName = "verifyDescriptionFieldSizeName"; + String groupDescription ="This text is to test that the description " + + "field takes no more than exactly 100 characters - actually."; + + assumeTrue("Description length is greater than 100 characters", + groupDescription.length() == 101); + + CreateVersionGroupPage groupPage = dashboardPage + .goToGroups() + .createNewGroup() + .inputGroupId(groupID) + .inputGroupName(groupName) + .inputGroupDescription(groupDescription) + .saveGroupFailure(); + + assertThat(groupPage.getFieldValidationErrors()) + .contains(CreateVersionGroupPage.LENGTH_ERROR) + .as("Invalid length error is shown"); + + groupDescription = groupDescription.substring(0, 100); + VersionGroupsPage verGroupsPage = groupPage + .clearFields() + .inputGroupId("verifyDescriptionFieldSizeID") + .inputGroupName(groupName) + .inputGroupDescription(groupDescription) + .saveGroup(); + + assertThat(verGroupsPage.getGroupNames()) + .contains(groupName) + .as("A group description of 100 chars is valid"); + } + + @Feature(summary = "The administrator can add a project version to " + + "a newly created group", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 170109) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void addANewProjectVersionToAnEmptyGroup() throws Exception { + String groupID = "add-version-to-empty-group"; + String groupName = "AddVersionToEmptyGroup"; + VersionGroupPage versionGroupPage = dashboardPage + .goToGroups() + .createNewGroup() + .inputGroupId(groupID) + .inputGroupName(groupName) + .saveGroup() + .goToGroup(groupName) + .clickProjectsTab() + .clickAddProjectVersionsButton() + .enterProjectVersion("about-fedora") + .selectProjectVersion("about-fedora master") + .clickProjectsTab(); + + assertThat(versionGroupPage.getProjectVersionsInGroup()) + .contains("about fedora\nmaster") + .as("The version group shows in the list"); + } + + @Feature(summary = "The administrator can use numbers, letters, periods, " + + "underscores and hyphens to create a group", + tcmsTestPlanIds = 5316, tcmsTestCaseIds = 396261) + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) + public void groupIdCharactersAreAcceptable() throws Exception { + String groupID = "test-_.1"; + String groupName = "TestValidIdCharacters"; + VersionGroupPage versionGroupPage = dashboardPage + .goToGroups() + .createNewGroup() + .inputGroupId(groupID) + .inputGroupName(groupName) + .saveGroup() + .goToGroup(groupName); + + assertThat(versionGroupPage.getGroupName()) + .isEqualTo(groupName) + .as("The group was created"); + } +} diff --git a/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupUrlTest.java b/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupUrlTest.java index 067dc6231f..baa96dd02a 100644 --- a/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupUrlTest.java +++ b/functional-test/src/test/java/org/zanata/feature/versionGroup/VersionGroupUrlTest.java @@ -64,7 +64,7 @@ public void setUp() { dashboardPage = new LoginWorkFlow().signIn("admin", "admin"); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void testUrlChangeUpdatesActiveElements() { VersionGroupPage versionGroupPage = createVersionGroup(); testBasicGroupUrl(versionGroupPage); @@ -74,7 +74,7 @@ private void testBasicGroupUrl(VersionGroupPage versionGroupPage) { assertThat(versionGroupPage.isLanguagesTabActive(), is(true)); } - @Test + @Test(timeout = ZanataTestCase.MAX_SHORT_TEST_DURATION) public void testTabClicksChangeUrl() { VersionGroupPage versionGroupPage = createVersionGroup(); diff --git a/functional-test/src/test/java/org/zanata/util/AddUsersRule.java b/functional-test/src/test/java/org/zanata/util/AddUsersRule.java index 6abbccc77b..c534a57a99 100644 --- a/functional-test/src/test/java/org/zanata/util/AddUsersRule.java +++ b/functional-test/src/test/java/org/zanata/util/AddUsersRule.java @@ -23,9 +23,7 @@ protected void before() throws Exception { deleteExceptEssentialData(); makeSampleUsers(); makeSampleLanguages(); - userJoinsLanguageTeam("translator", - Sets.newHashSet(LocaleId.FR, new LocaleId("hi"), - new LocaleId("pl"))); + userJoinsLanguageTeam("translator", "fr,hi,pl"); } @Override diff --git a/functional-test/src/test/java/org/zanata/util/EnsureLogoutRule.java b/functional-test/src/test/java/org/zanata/util/EnsureLogoutRule.java new file mode 100644 index 0000000000..ab92d4e635 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/util/EnsureLogoutRule.java @@ -0,0 +1,39 @@ +package org.zanata.util; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.zanata.page.utility.HomePage; +import org.zanata.workflow.BasicWorkFlow; + +/** + * A test rule that will ensure tests have a clean browser session before and + * after. + * + * @author Patrick Huang pahuang@redhat.com + */ +public class EnsureLogoutRule implements TestRule { + @Override + public Statement apply(final Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + logoutIfLoggedIn(); + try { + base.evaluate(); + } finally { + logoutIfLoggedIn(); + } + } + }; + } + + private static HomePage logoutIfLoggedIn() { + HomePage homePage = new BasicWorkFlow().goToHome(); + if (homePage.hasLoggedIn()) { + homePage.logout(); + } + return homePage; + } +} diff --git a/functional-test/src/test/java/org/zanata/util/FeatureEntry.java b/functional-test/src/test/java/org/zanata/util/FeatureEntry.java new file mode 100644 index 0000000000..019f603048 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/util/FeatureEntry.java @@ -0,0 +1,101 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.util; + +import java.util.Collections; +import java.util.List; + +import org.codehaus.jackson.annotate.JsonAutoDetect; +import org.zanata.feature.Feature; + +import com.google.common.primitives.Ints; + +/** + * This object will be converted to JSON. + * @see org.zanata.util.FeatureInventoryRecorder + * + * @author Patrick Huang pahuang@redhat.com + */ +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, + getterVisibility = JsonAutoDetect.Visibility.NONE, + setterVisibility = JsonAutoDetect.Visibility.NONE) +public class FeatureEntry { + private String testName; + private String category; + private String summary; + private String testResult; + private int bugzilla; + private List testIds; + private List planIds; + + @SuppressWarnings("unused") + FeatureEntry() { + // used by JSON serializer/deserializer + } + + public FeatureEntry(Feature feature, String displayName, + TestResult result) { + testName = displayName; + category = getLastPackageName(displayName); + summary = feature.summary(); + bugzilla = feature.bugzilla(); + testIds = toList(feature.tcmsTestCaseIds()); + planIds = toList(feature.tcmsTestPlanIds()); + testResult = result.name(); + } + + private static List toList(int[] ints) { + if (ints == null) { + return Collections.emptyList(); + } + return Ints.asList(ints); + } + + /** + * quick and dirty way to generate category. Currently it assumes last + * package name is category. i.e. if the test name is + * changePasswordAreOfRequiredLength + * (org.zanata.feature.account.ChangePasswordTest), the category will be + * considered as account. + * + * @param testDisplayName + * JUnit test display name + * @return category name + */ + private static String getLastPackageName(String testDisplayName) { + try { + int lastDot = testDisplayName.lastIndexOf("."); + String strippedClassName = testDisplayName.substring(0, lastDot); + int secondLastDot = strippedClassName.lastIndexOf("."); + String lastPackageName = strippedClassName + .substring(secondLastDot + 1, strippedClassName.length()); + return lastPackageName; + } catch (Exception e) { + // in case something goes wrong + return "None"; + } + } + + public static enum TestResult { + Passed, Failed, Ignored + } +} diff --git a/functional-test/src/test/java/org/zanata/util/FeatureInventoryRecorder.java b/functional-test/src/test/java/org/zanata/util/FeatureInventoryRecorder.java new file mode 100644 index 0000000000..3e98bc2d43 --- /dev/null +++ b/functional-test/src/test/java/org/zanata/util/FeatureInventoryRecorder.java @@ -0,0 +1,124 @@ +package org.zanata.util; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.codehaus.jackson.map.ObjectMapper; +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.zanata.feature.Feature; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; + +/** + * @author Patrick Huang pahuang@redhat.com + */ +public class FeatureInventoryRecorder extends RunListener { + + private boolean fileReport; + private ThreadLocal currentFeature = new ThreadLocal(); + private File report; + private ObjectMapper objectMapper = new ObjectMapper(); + private List entries = Lists.newArrayList(); + + @Override + public void testRunStarted(Description description) throws Exception { + super.testRunStarted(description); + String locationPath = + System.getProperty("featureInventoryLocation", + "./target/feature-inventory"); + File location = new File(locationPath); + report = new File(location, "features.json"); + location.mkdirs(); + fileReport = report.createNewFile(); + } + + @Override + public void testRunFinished(Result result) throws Exception { + super.testRunFinished(result); + objectMapper.writerWithDefaultPrettyPrinter() + .writeValue(report, entries); + } + + @Override + public void testStarted(Description description) throws Exception { + super.testStarted(description); + Optional featureOptional = getFeature(description); + if (featureOptional.isPresent()) { + currentFeature.set(featureOptional.get()); + } + } + + /** + * annotation on method takes precedence over annotation on class. At the + * moment class level annotation will cause multiple entries in the result + * if there are more than one test methods. + */ + private static Optional getFeature(Description description) { + Feature testClassFeature = + description.getTestClass().getAnnotation(Feature.class); + Feature testMethodFeature = description.getAnnotation(Feature.class); + return Optional.fromNullable(testMethodFeature).or( + Optional.fromNullable(testClassFeature)); + } + + @Override + public void testFinished(Description description) throws Exception { + super.testFinished(description); + reportFeature(FeatureEntry.TestResult.Passed, + description.getDisplayName()); + } + + @Override + public void testFailure(Failure failure) throws Exception { + super.testFailure(failure); + reportFeature(FeatureEntry.TestResult.Failed, failure + .getDescription() + .getDisplayName()); + } + + @Override + public void testIgnored(Description description) throws Exception { + super.testIgnored(description); + Optional featureOptional = getFeature(description); + if (featureOptional.isPresent()) { + currentFeature.set(featureOptional.get()); + } + reportFeature(FeatureEntry.TestResult.Ignored, + description.getDisplayName()); + } + + private void reportFeature(FeatureEntry.TestResult result, + String displayName) { + if (currentFeature.get() == null) { + return; + } + Feature feature = currentFeature.get(); + FeatureEntry entry = new FeatureEntry(feature, displayName, result); + if (fileReport) { + entries.add(entry); + + } else { + // display to console + try { + Object json = + objectMapper.readValue( + objectMapper.writeValueAsString(entry), + FeatureEntry.class); + System.out.println(objectMapper + .writerWithDefaultPrettyPrinter() + .writeValueAsString(json)); + } catch (IOException e) { + System.out.println("Error writing as JSON"); + e.printStackTrace(); + } + + } + currentFeature.remove(); + } +} diff --git a/functional-test/src/test/java/org/zanata/util/HasEmailRule.java b/functional-test/src/test/java/org/zanata/util/HasEmailRule.java index 3605f51a74..b4792bd2ef 100644 --- a/functional-test/src/test/java/org/zanata/util/HasEmailRule.java +++ b/functional-test/src/test/java/org/zanata/util/HasEmailRule.java @@ -32,6 +32,7 @@ public void evaluate() throws Throwable { try { base.evaluate(); } finally { + wiser.getMessages().clear(); wiser.stop(); } } diff --git a/functional-test/src/test/java/org/zanata/util/SampleDataResourceClient.java b/functional-test/src/test/java/org/zanata/util/SampleDataResourceClient.java index 4676830f73..4d0eee3b7c 100644 --- a/functional-test/src/test/java/org/zanata/util/SampleDataResourceClient.java +++ b/functional-test/src/test/java/org/zanata/util/SampleDataResourceClient.java @@ -44,12 +44,18 @@ public static void makeSampleUsers() throws Exception { checkAndReleaseConnection(createRequest("/users").put()); } + /** + * @param username + * username to join language team + * @param localesCSV + * locale ids separated by comma + */ public static void userJoinsLanguageTeam(String username, - Set locales) throws Exception { + String localesCSV) throws Exception { ClientRequest request = createRequest("/accounts/u/" + username + "/languages"); - checkAndReleaseConnection(request.queryParameter("locales", locales) + checkAndReleaseConnection(request.queryParameter("locales", localesCSV) .put()); } diff --git a/functional-test/src/test/java/org/zanata/util/SampleProjectRule.java b/functional-test/src/test/java/org/zanata/util/SampleProjectRule.java index acd5f328ee..a7c03f03c6 100644 --- a/functional-test/src/test/java/org/zanata/util/SampleProjectRule.java +++ b/functional-test/src/test/java/org/zanata/util/SampleProjectRule.java @@ -42,9 +42,7 @@ public void before() throws Throwable { deleteExceptEssentialData(); makeSampleUsers(); makeSampleLanguages(); - Set locales = - Sets.newHashSet(LocaleId.FR, new LocaleId("hi"), - new LocaleId("pl")); + String locales = "fr,hi,pl"; userJoinsLanguageTeam("translator", locales); userJoinsLanguageTeam("glossarist", locales); makeSampleProject(); diff --git a/functional-test/src/test/resources/conf/standalone.xml b/functional-test/src/test/resources/conf/standalone.xml index 46e6a92db4..497e138b1b 100644 --- a/functional-test/src/test/resources/conf/standalone.xml +++ b/functional-test/src/test/resources/conf/standalone.xml @@ -23,7 +23,7 @@ - + @@ -329,7 +329,7 @@ - + diff --git a/functional-test/src/test/resources/feature-inventory/app.js b/functional-test/src/test/resources/feature-inventory/app.js new file mode 100644 index 0000000000..14625f74a9 --- /dev/null +++ b/functional-test/src/test/resources/feature-inventory/app.js @@ -0,0 +1,21 @@ +var featureApp = angular.module('featureApp', [ + 'ngRoute', + 'featureControllers', + 'featureFilters' +]); + +featureApp.config(['$routeProvider', + function($routeProvider) { + $routeProvider. + when('/features', { + templateUrl: 'partials/list.html', + controller: 'FeatureListCtrl' + }). + when('/features/:testName', { + templateUrl: 'partials/detail.html', + controller: 'FeatureDetailCtrl' + }). + otherwise({ + redirectTo: '/features' + }); + }]); diff --git a/functional-test/src/test/resources/feature-inventory/controllers.js b/functional-test/src/test/resources/feature-inventory/controllers.js new file mode 100644 index 0000000000..0b3c161784 --- /dev/null +++ b/functional-test/src/test/resources/feature-inventory/controllers.js @@ -0,0 +1,30 @@ +var featureControllers = angular.module('featureControllers', []); + +var FeatureListCtrl = function($scope, $http, $location, $filter) { + $http.get('features.json').success(function(data) { + $scope.features = data; + }); + + $scope.orderProp = 'category'; + $scope.featureDetail = function(index) { + $location.path("/features/" + index); + }; +}; + +var FeatureDetailCtrl = function($scope, $http, $routeParams, filterFilter) { + $http.get('features.json').success(function(data) { + var filtered = filterFilter(data, {testName: $routeParams.testName}); + if (filtered.length == 1) { + $scope.feature = filtered[0]; + } else { + $scope.warning = + "Something wrong with the URL. Can't find test name in features."; + } + }); +}; + +featureControllers.controller('FeatureListCtrl', [ '$scope', '$http', + '$location', '$filter', FeatureListCtrl ]); + +featureControllers.controller('FeatureDetailCtrl', [ '$scope', '$http', + '$routeParams', 'filterFilter', FeatureDetailCtrl ]); diff --git a/functional-test/src/test/resources/feature-inventory/filter.js b/functional-test/src/test/resources/feature-inventory/filter.js new file mode 100644 index 0000000000..e989cd7561 --- /dev/null +++ b/functional-test/src/test/resources/feature-inventory/filter.js @@ -0,0 +1,12 @@ +var resultStyle = function () { + return function(result) { + if (result == 'Passed') { + return "label--success"; + } else if (result == 'Ignored') { + return "label--unsure"; + } else { + return "label--danger"; + } + }; +}; +angular.module('featureFilters', []).filter('resultStyle', resultStyle); \ No newline at end of file diff --git a/functional-test/src/test/resources/feature-inventory/index.html b/functional-test/src/test/resources/feature-inventory/index.html new file mode 100644 index 0000000000..ec3063f7d3 --- /dev/null +++ b/functional-test/src/test/resources/feature-inventory/index.html @@ -0,0 +1,18 @@ + + + Zanata Features + + + + + + + + + +

+ + + diff --git a/functional-test/src/test/resources/feature-inventory/partials/detail.html b/functional-test/src/test/resources/feature-inventory/partials/detail.html new file mode 100644 index 0000000000..0ef919e806 --- /dev/null +++ b/functional-test/src/test/resources/feature-inventory/partials/detail.html @@ -0,0 +1,18 @@ +
+ < Back to features list +

{{feature.summary}}

+ {{feature.testResult}} +

{{feature.testName}}

+ + {{warning}} +
diff --git a/functional-test/src/test/resources/feature-inventory/partials/list.html b/functional-test/src/test/resources/feature-inventory/partials/list.html new file mode 100644 index 0000000000..1cc1e424d1 --- /dev/null +++ b/functional-test/src/test/resources/feature-inventory/partials/list.html @@ -0,0 +1,41 @@ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+ diff --git a/functional-test/src/test/resources/test-tmx.xml b/functional-test/src/test/resources/test-tmx.xml new file mode 100644 index 0000000000..21c5650218 --- /dev/null +++ b/functional-test/src/test/resources/test-tmx.xml @@ -0,0 +1,18 @@ + + + +
+ + + + Fedora is an open, innovative, forward looking operating system and platform, based on Linux, that is always free for anyone to use, modify and distribute, now and forever. It is developed by a large community of people who strive to provide and maintain the very best in free, open source software and standards. Fedora is part of the Fedora Project, sponsored by Red Hat, Inc. + + + This is a TM Import Test + + + + diff --git a/pom.xml b/pom.xml index d2ab13b5c7..9f55b7362a 100644 --- a/pom.xml +++ b/pom.xml @@ -2,13 +2,13 @@ 4.0.0 server - 3.4.3-SNAPSHOT + 3.5.0-SNAPSHOT Zanata server modules pom org.zanata zanata-parent - 19 + 20-SNAPSHOT ../parent @@ -16,34 +16,40 @@ scm:git:git://github.com/zanata/zanata-server.git scm:git:git@github.com:zanata/zanata-server.git https://github.com/zanata/zanata-server - HEAD + 2.1.2 50 30 false ${project.build.directory}/delombok/org/zanata - 2.5.0 - 4.8 + 14.0.1 + 2.5.1 + 50.1.1 ${project.build.sourceDirectory}/org/zanata 3.6.2 2.3.1.Final 1.2.1 0.22 - 3.3.1 + 3.4.0-SNAPSHOT - 3.3.0 + 3.3.1 3.3.1 3.3.0 4.3.4.Final + 2.0.0-alpha-5 provided - 4.2.7.SP1 + + 4.2.8.Final compile org.jboss.resteasy @@ -112,7 +132,16 @@ pom + + org.jboss.as + jboss-as-parent + ${jboss.as.version} + pom + import + + org.jboss.seam bom @@ -122,11 +151,39 @@ - org.jboss.as - jboss-as-parent - ${jboss.as.version} - pom - import + commons-beanutils + commons-beanutils + 1.9.2 + + + commons-logging + commons-logging + + + + + + org.apache.httpcomponents + httpcore + 4.2.3 + + + + org.apache.maven + maven-aether-provider + 3.0.5 + + + + org.apache.maven.wagon + wagon-provider-api + 2.4 + + + + org.apache.maven.wagon + wagon-http-lightweight + 2.4 @@ -136,6 +193,78 @@ test + + org.jboss.byteman + byteman + ${byteman.version} + + + + org.jboss.byteman + byteman-bmunit + ${byteman.version} + + + + org.jboss.byteman + byteman-install + ${byteman.version} + + + + org.jboss.byteman + byteman-submit + ${byteman.version} + + + + org.jboss.com.sun.httpserver + httpserver + 1.0.1.Final + + + + org.jboss.shrinkwrap.descriptors + shrinkwrap-descriptors-api-base + ${shrinkwrap.desc.version} + + + + org.jboss.shrinkwrap.descriptors + shrinkwrap-descriptors-api-javaee + ${shrinkwrap.desc.version} + + + + org.jboss.shrinkwrap.descriptors + shrinkwrap-descriptors-api-jboss + ${shrinkwrap.desc.version} + + + + org.jboss.shrinkwrap.descriptors + shrinkwrap-descriptors-impl-base + ${shrinkwrap.desc.version} + + + + org.jboss.shrinkwrap.descriptors + shrinkwrap-descriptors-impl-javaee + ${shrinkwrap.desc.version} + + + + org.jboss.shrinkwrap.descriptors + shrinkwrap-descriptors-impl-jboss + ${shrinkwrap.desc.version} + + + + org.jboss.shrinkwrap.descriptors + shrinkwrap-descriptors-spi + ${shrinkwrap.desc.version} + + org.opensymphony.quartz quartz @@ -147,6 +276,16 @@ org.zanata zanata-common-api ${zanata.api.version} + + + javax.servlet + servlet-api + + + javax.annotation + jsr250-api + + @@ -172,6 +311,17 @@ zanata-rest-client ${zanata.client.version} test + + + + org.jboss.resteasy + resteasy-jaxrs + + + org.jboss.resteasy + jaxrs-api + + org.zanata @@ -210,6 +360,7 @@ com.google.gwt.inject gin 1.5.0 + provided com.google.inject @@ -256,6 +407,7 @@ de.novanic.gwteventservice gwteventservice ${gwteventservice.version} + provided de.novanic.gwteventservice @@ -340,6 +492,18 @@ + + net.sf.okapi.filters + okapi-filter-regex + ${okapi.version} + + + net.sf.okapi.logbind + build-log4j + + + + net.sf.okapi.steps okapi-step-tokenization @@ -404,6 +568,12 @@ ${hibernate.search.scope} + + org.hibernate.common + hibernate-commons-annotations + 4.0.4.Final + + org.hibernate hibernate-core @@ -440,12 +610,36 @@ ${hibernate.version} + + org.javassist + javassist + 3.18.2-GA + + org.jboss.el jboss-el 1.0_02.CR6 + + org.jboss.logging + jboss-logging + 3.1.3.GA + + + + org.jboss.logging + jboss-logging-annotations + 1.2.0.Final + + + + org.jboss.logging + jboss-logging-processor + 1.2.0.Final + + org.jboss.seam jboss-seam @@ -475,6 +669,10 @@ commons-httpclient commons-httpclient + + javax.servlet + servlet-api + org.apache.solr solr-solrj @@ -518,7 +716,7 @@ net.customware.gwt.presenter gwt-presenter 1.1.1 - compile + provided @@ -560,7 +758,7 @@ org.fedorahosted.tennera jgettext - 0.11 + 0.13 org.functionaljava @@ -582,14 +780,6 @@ - - - - javax.xml.stream - stax-api - 1.0 - - @@ -638,6 +828,17 @@ false + + + repo.bodar.com + http://repo.bodar.com + + true + + + false + + @@ -687,22 +888,11 @@ maven-enforcer-plugin - - - - - org.projectlombok - lombok - - com.sun.jna.* - - - - jboss-public-repository-group okapi-cloudbees-release + repo.bodar.com cobertura-it-maven-plugin-maven2-release @@ -733,7 +923,7 @@ org.codehaus.mojo cobertura-maven-plugin - 2.5.1 + 2.6 xml @@ -788,58 +978,6 @@ - - - jboss7 - - true - - - - org.slf4j - slf4j-api - provided - - - commons-collections - commons-collections - provided - - - commons-logging - commons-logging - provided - - - javassist - javassist - provided - - - javax.faces - jsf-api - provided - - - javax.faces - jsf-impl - provided - - - com.google.gwt - gwt-user - provided - - - net.customware.gwt.presenter - gwt-presenter - 1.1.1 - provided - - - - - delombok diff --git a/zanata-model/pom.xml b/zanata-model/pom.xml index ae2867e64d..110343a794 100644 --- a/zanata-model/pom.xml +++ b/zanata-model/pom.xml @@ -4,7 +4,7 @@ org.zanata server - 3.4.3-SNAPSHOT + 3.5.0-SNAPSHOT zanata-model Zanata model @@ -15,7 +15,6 @@ scm:git:git://github.com/zanata/zanata.git scm:git:git@github.com:zanata/zanata.git https://github.com/zanata/zanata - HEAD @@ -33,7 +32,6 @@ maven-dependency-plugin - true org.projectlombok:lombok org.hibernate:hibernate-search @@ -144,6 +142,29 @@ junit test + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + 1.6.0 + test + + + + commons-beanutils + commons-beanutils + 1.9.1 + + + commons-logging + commons-logging + + + org.zanata @@ -282,7 +303,7 @@ com.google.code.findbugs - jsr305 + annotations org.zanata diff --git a/zanata-model/src/main/java/org/zanata/model/HApplicationConfiguration.java b/zanata-model/src/main/java/org/zanata/model/HApplicationConfiguration.java index 40ac9a634e..e228f6f1e0 100644 --- a/zanata-model/src/main/java/org/zanata/model/HApplicationConfiguration.java +++ b/zanata-model/src/main/java/org/zanata/model/HApplicationConfiguration.java @@ -59,6 +59,7 @@ public class HApplicationConfiguration extends ModelEntityBase { public static String KEY_TERMS_CONDITIONS_URL = "terms.conditions.url"; public static String KEY_MAX_CONCURRENT_REQ_PER_API_KEY = "max.concurrent.req.per.apikey"; public static String KEY_MAX_ACTIVE_REQ_PER_API_KEY = "max.active.req.per.apikey"; + public static String KEY_MAX_FILES_PER_UPLOAD = "fileupload.max.files.per.upload"; private static final long serialVersionUID = 8652817113098817448L; diff --git a/zanata-model/src/main/java/org/zanata/model/HGlossaryEntry.java b/zanata-model/src/main/java/org/zanata/model/HGlossaryEntry.java index acb374a29c..55ce90816f 100644 --- a/zanata-model/src/main/java/org/zanata/model/HGlossaryEntry.java +++ b/zanata-model/src/main/java/org/zanata/model/HGlossaryEntry.java @@ -78,6 +78,7 @@ public String getSourceRef() { return sourceRef; } + //TODO: this should be many to one @OneToOne @JoinColumn(name = "srcLocaleId", nullable = false) @Field(analyze = Analyze.NO) diff --git a/zanata-model/src/main/java/org/zanata/model/HPerson.java b/zanata-model/src/main/java/org/zanata/model/HPerson.java index a05e107878..c8091cea07 100644 --- a/zanata-model/src/main/java/org/zanata/model/HPerson.java +++ b/zanata-model/src/main/java/org/zanata/model/HPerson.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.Set; +import javax.annotation.Nonnull; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; @@ -135,7 +136,7 @@ protected Set getLanguageTeamMemberships() { } @Transient - public boolean isMaintainer(HProject proj) { + public boolean isMaintainer(@Nonnull HProject proj) { // TODO consider implementing business key equality and using // getMaintainerProjects().contains(proj) for (HProject project : getMaintainerProjects()) { diff --git a/zanata-model/src/main/java/org/zanata/model/HRawDocument.java b/zanata-model/src/main/java/org/zanata/model/HRawDocument.java index f5ad442463..db95014894 100644 --- a/zanata-model/src/main/java/org/zanata/model/HRawDocument.java +++ b/zanata-model/src/main/java/org/zanata/model/HRawDocument.java @@ -63,9 +63,7 @@ public HDocument getDocument() { } public void setDocument(HDocument document) { - if (!Objects.equal(this.document, document)) { - this.document = document; - } + this.document = document; } @NotEmpty @@ -89,7 +87,5 @@ public String toString() { + ",versionNum=" + versionNum + ",contentHash=" + contentHash + "]"; } - // TODO override equals to use contentHash, type, parameters, etc. - } diff --git a/zanata-model/src/main/java/org/zanata/model/HSimpleComment.java b/zanata-model/src/main/java/org/zanata/model/HSimpleComment.java index 515ad459d8..7511281713 100644 --- a/zanata-model/src/main/java/org/zanata/model/HSimpleComment.java +++ b/zanata-model/src/main/java/org/zanata/model/HSimpleComment.java @@ -30,7 +30,6 @@ import javax.persistence.EntityListeners; import javax.persistence.GeneratedValue; import javax.persistence.Id; -import javax.persistence.PostPersist; import javax.persistence.PrePersist; import javax.persistence.PreUpdate; import javax.persistence.Temporal; @@ -44,23 +43,21 @@ import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Type; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * @see org.zanata.rest.dto.extensions.comment.SimpleComment * */ @Entity -@EntityListeners({HSimpleComment.EntityListener.class}) +@EntityListeners({ HSimpleComment.EntityListener.class }) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @BatchSize(size = 20) @Setter @NoArgsConstructor public class HSimpleComment implements HashableState, Serializable { private static final long serialVersionUID = 5684831285769022524L; - private Long id; + private Long id; private String comment; protected Date lastChanged; diff --git a/zanata-model/src/main/java/org/zanata/model/HTextContainer.java b/zanata-model/src/main/java/org/zanata/model/HTextContainer.java index 23ee3699e6..f03b8700f3 100644 --- a/zanata-model/src/main/java/org/zanata/model/HTextContainer.java +++ b/zanata-model/src/main/java/org/zanata/model/HTextContainer.java @@ -63,7 +63,7 @@ @Parameter(name = "maxGramSize", value = "1") }), filters = { @TokenFilterDef( factory = LowerCaseFilterFactory.class) }) }) -abstract class HTextContainer implements HasContents, Serializable { +public abstract class HTextContainer implements HasContents, Serializable { private static final long serialVersionUID = 1L; @SuppressWarnings("unused") diff --git a/zanata-model/src/main/java/org/zanata/model/HTextFlow.java b/zanata-model/src/main/java/org/zanata/model/HTextFlow.java index cd0dfcb081..7ca8078b15 100644 --- a/zanata-model/src/main/java/org/zanata/model/HTextFlow.java +++ b/zanata-model/src/main/java/org/zanata/model/HTextFlow.java @@ -48,7 +48,6 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -import com.google.common.annotations.VisibleForTesting; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.Setter; @@ -64,7 +63,6 @@ import org.hibernate.search.annotations.Analyze; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.FieldBridge; -import org.hibernate.search.annotations.Indexed; import org.hibernate.validator.constraints.NotEmpty; import org.zanata.common.HasContents; import org.zanata.common.LocaleId; @@ -74,6 +72,7 @@ import org.zanata.util.OkapiUtil; import org.zanata.util.StringUtil; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; import com.google.common.collect.ImmutableList; diff --git a/zanata-model/src/main/java/org/zanata/model/HTextFlowTarget.java b/zanata-model/src/main/java/org/zanata/model/HTextFlowTarget.java index ad8322dad6..9f6cf7b65e 100644 --- a/zanata-model/src/main/java/org/zanata/model/HTextFlowTarget.java +++ b/zanata-model/src/main/java/org/zanata/model/HTextFlowTarget.java @@ -222,13 +222,13 @@ public String getContent() { @Deprecated @Transient + @NotEmpty public void setContent(String content) { this.setContents(Arrays.asList(content)); } @Override @Transient - @NotEmpty // TODO extend HTextContainer and remove this @Field(name = IndexFieldLabels.CONTENT, bridge = @FieldBridge( impl = StringListBridge.class, params = { diff --git a/zanata-model/src/main/java/org/zanata/model/HTextFlowTargetHistory.java b/zanata-model/src/main/java/org/zanata/model/HTextFlowTargetHistory.java index 5c87562fae..8b1029537c 100644 --- a/zanata-model/src/main/java/org/zanata/model/HTextFlowTargetHistory.java +++ b/zanata-model/src/main/java/org/zanata/model/HTextFlowTargetHistory.java @@ -222,11 +222,11 @@ public HPerson getReviewer() { return reviewer; } - protected void setTranslator(HPerson translator) { + public void setTranslator(HPerson translator) { this.translator = translator; } - protected void setReviewer(HPerson reviewer) { + public void setReviewer(HPerson reviewer) { this.reviewer = reviewer; } diff --git a/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java b/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java index d935408f67..abcb1c314e 100644 --- a/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java +++ b/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java @@ -47,13 +47,16 @@ import com.google.common.annotations.VisibleForTesting; -@EntityListeners({ModelEntityBase.EntityListener.class}) +@EntityListeners({ ModelEntityBase.EntityListener.class }) @MappedSuperclass public class ModelEntityBase implements Serializable, HashableState { private static final long serialVersionUID = -6139220551322868743L; + protected Long id; + protected Date creationDate; + protected Date lastChanged; protected Integer versionNum; @@ -89,6 +92,7 @@ public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } + // TODO extract lastChanged from ModelEntityBase and use with @Embedded // NB: also used in HSimpleComment @Temporal(TemporalType.TIMESTAMP) diff --git a/zanata-model/src/main/java/org/zanata/model/po/HPotEntryData.java b/zanata-model/src/main/java/org/zanata/model/po/HPotEntryData.java index 33ea9cb329..1591e30cc0 100644 --- a/zanata-model/src/main/java/org/zanata/model/po/HPotEntryData.java +++ b/zanata-model/src/main/java/org/zanata/model/po/HPotEntryData.java @@ -129,5 +129,4 @@ public void setReferences(String references) { public String getReferences() { return references; } - } diff --git a/zanata-model/src/main/java/org/zanata/model/validator/Slug.java b/zanata-model/src/main/java/org/zanata/model/validator/Slug.java index aa77a29121..f0c3e9d02f 100644 --- a/zanata-model/src/main/java/org/zanata/model/validator/Slug.java +++ b/zanata-model/src/main/java/org/zanata/model/validator/Slug.java @@ -30,7 +30,7 @@ /** * A slug is a short label for something, containing only letters, numbers, - * underscores or hyphens. It is typically used in urls + * periods, underscores or hyphens. It is typically used in urls * * @author asgeirf * diff --git a/zanata-model/src/main/java/org/zanata/util/JPACopier.java b/zanata-model/src/main/java/org/zanata/util/JPACopier.java new file mode 100644 index 0000000000..84a8d29551 --- /dev/null +++ b/zanata-model/src/main/java/org/zanata/util/JPACopier.java @@ -0,0 +1,346 @@ +package org.zanata.util; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nonnull; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.apache.commons.beanutils.PropertyUtilsBean; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.reflect.FieldUtils; +import org.hibernate.proxy.HibernateProxyHelper; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.primitives.Primitives; +import lombok.extern.slf4j.Slf4j; + +// @formatter:off +/** + * Utility class for creating copy of Hibernate entity in + * {@link org.zanata.model}. + * + * This will copy all writable properties {@link PropertyUtilsBean#isWriteable} + * in provided bean except for: + * + * Properties in {@link this#COMMON_IGNORED_FIELDS}, and + * Properties in ignoreProperties field. + * + * @see this#shouldCopy(PropertyUtilsBean, Object, String, java.util.List) + * for condition check. + * + * + * Property which has {@link javax.persistence.OneToMany#mappedBy()} or + * {@link javax.persistence.OneToOne} in field or GetterMethod {@link PropertyUtilsBean#getReadMethod} + * will be copied using {@link this#copyBean(Object, String...)}, + * otherwise {@link BeanUtilsBean#copyProperty} will be used. + * + * New collection will be created if bean type is: {@link java.util.List}, + * {@link java.util.Set} and {@link java.util.Map} + * + * + * @see this#copyBean(Object, String...) + * @see this#copyBean(Object, Object, String...) + * + * + * @author Alex Eng aeng@redhat.com + */ +// @formatter:on +@Slf4j +public class JPACopier { + + /** + * Common ignored fields when copying entity, {id, creationDate, + * lastChanged} + */ + private static final List COMMON_IGNORED_FIELDS = ImmutableList + . builder().add("id").add("creationDate").build(); + + /** + * Fields to copy using {@link this#copyBean(Object, String...)} in class. + */ + private static Map> FIELDS_TO_COPY = Maps + .newConcurrentMap(); + + /** + * Create a clone of all writable properties from fromBean. + * + * @param fromBean + * original bean to be copy from. Needs to have no-arguments + * constructor. + * @param ignoreProperties + * properties to be ignore when copy + * @throws IllegalAccessException + * @throws InstantiationException + * @throws InvocationTargetException + * @throws NoSuchMethodException + */ + public static T copyBean(@Nonnull T fromBean, + String... ignoreProperties) + throws IllegalAccessException, InstantiationException, + InvocationTargetException, NoSuchMethodException { + Preconditions.checkNotNull(fromBean); + + // create a copy of the bean entity + // TODO: replace HibernateProxyHelper as its being phased out + Object copy = HibernateProxyHelper.getClassWithoutInitializingProxy( + fromBean).newInstance(); + + copy = copyBean(fromBean, copy, ignoreProperties); + return (T) copy; + } + + /** + * Create a clone of all writable properties from fromBean. + * + * @param fromBean + * original bean to be copy from + * @param toBean + * destination bean + * @param ignoreProperties + * properties to be ignore when copy + * @throws IllegalAccessException + * @throws InstantiationException + * @throws InvocationTargetException + * @throws NoSuchMethodException + * + * @return fromBean if + * {@link org.zanata.util.JPACopier#isPrimitiveOrString(Object)}, + * otherwise return toBean + */ + public static T copyBean(@Nonnull T fromBean, + @Nonnull T toBean, String... ignoreProperties) + throws IllegalAccessException, InstantiationException, + InvocationTargetException, NoSuchMethodException { + + Preconditions.checkNotNull(fromBean); + Preconditions.checkNotNull(toBean); + + if (isPrimitiveOrString(fromBean)) { + return fromBean; + } + + BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance(); + + if (isCollectionType(fromBean.getClass())) { + toBean = (T) createNewCollection(fromBean.getClass(), fromBean); + return toBean; + } + + List ignoreList = Lists.newArrayList(ignoreProperties); + + Map propertiesMap = + beanUtilsBean.getPropertyUtils().describe(fromBean); + + for (Map.Entry entry : propertiesMap.entrySet()) { + String property = entry.getKey(); + Object value = entry.getValue(); + + if (!shouldCopy(beanUtilsBean.getPropertyUtils(), toBean, property, + ignoreList)) { + continue; + } + + if (value != null && isJPACopyProperty(fromBean, property)) { + value = copyBean(value); + } + copyProperty(beanUtilsBean, toBean, property, value); + } + return toBean; + } + + /** + * Check if property is writable and not in ignore list and common ignore + * list. + * + * @param propertyUtilsBean + * @param toBean + * @param property + * @param ignoreList + */ + private static boolean shouldCopy(PropertyUtilsBean propertyUtilsBean, + Object toBean, String property, List ignoreList) { + return propertyUtilsBean.isWriteable(toBean, property) + && !ignoreList.contains(property) + && !COMMON_IGNORED_FIELDS.contains(property); + } + + /** + * Check is property is a JPA copier field + * + * @param bean + * @param property + */ + private static boolean isJPACopyProperty(Object bean, String property) + throws IllegalAccessException, NoSuchMethodException, + InvocationTargetException { + if (!FIELDS_TO_COPY.containsKey(bean.getClass())) { + FIELDS_TO_COPY.put(bean.getClass(), getJPACopierFields(bean)); + } + return FIELDS_TO_COPY.get(bean.getClass()).contains(property); + } + + /** + * Check if obj is Primitive type or {@link java.lang.String} + * + * @see Class#isPrimitive() + * @param obj + * + */ + private static boolean isPrimitiveOrString(Object obj) { + return obj instanceof String + || Primitives.isWrapperType(Primitives.wrap(obj.getClass())); + } + + /** + * Copy value to property. New instance of value will be created if + * propertyType is {@link java.util.List}, {@link java.util.Set} or + * {@link java.util.Map}. + * + * Note: ArrayList, HashSet and HashMap are being used to create new + * instance of Collection, which will potential be an issue if propertyType + * is not one of those implementation but sharing the same interface. + * + */ + private static void + copyProperty(BeanUtilsBean beanUtilsBean, Object toBean, + String property, Object value) + throws InvocationTargetException, IllegalAccessException, + NoSuchMethodException { + + Class propertyType = + beanUtilsBean.getPropertyUtils().getPropertyDescriptor( + toBean, property).getPropertyType(); + + if (isCollectionType(propertyType)) { + value = createNewCollection(propertyType, value); + } + beanUtilsBean.copyProperty(toBean, property, value); + } + + /** + * Check if clazz is List, Set or Map + * + * @param clazz + */ + private static boolean isCollectionType(Class clazz) { + return clazz == List.class || clazz == Set.class || clazz == Map.class; + } + + /** + * Create new instance of collection is value.class is List, Set, or Map + * + * @param clazz + * @param value + */ + private static Object createNewCollection(Class clazz, Object value) { + if (value != null) { + if (clazz == List.class) { + List list = Lists. newArrayList(); + list.addAll((List) value); + return list; + } else if (clazz == Set.class) { + Set set = Sets. newHashSet(); + set.addAll((Set) value); + return set; + } else if (clazz == Map.class) { + Map map = Maps. newHashMap(); + map.putAll((Map) value); + return map; + } + } + return value; + } + + /** + * Return list of properties that should use JPACopier to copy. + * {@link javax.persistence.OneToMany#mappedBy()} + * {@link javax.persistence.OneToOne} + * + * This runs only once for each Class type. + * + * @param bean + * The actual bean of which fields will be extracted + * @throws IllegalAccessException + * @throws NoSuchMethodException + * @throws InvocationTargetException + */ + private static List getJPACopierFields(Object bean) + throws IllegalAccessException, NoSuchMethodException, + InvocationTargetException { + + PropertyUtilsBean propertyUtilsBean = + BeanUtilsBean.getInstance().getPropertyUtils(); + + List properties = Lists.newCopyOnWriteArrayList(); + + // TODO: replace HibernateProxyHelper as its being phased out + Class noProxyBean = + HibernateProxyHelper.getClassWithoutInitializingProxy(bean); + + Map propertiesMap = propertyUtilsBean.describe(bean); + + for (String property : propertiesMap.keySet()) { + // Read annotate in Field or Getter method of property + try { + PropertyDescriptor descriptor = propertyUtilsBean + .getPropertyDescriptor(bean, property); + + String methodName = + propertyUtilsBean.getReadMethod(descriptor).getName(); + + Method getterMethod = noProxyBean.getMethod(methodName); + if (isUseJPACopier(getterMethod)) { + properties.add(property); + continue; + } + } catch (NoSuchMethodException e) { + log.debug("Read method inaccessible for {0} in class-{1}", + property, noProxyBean.getName()); + } + Field field = + FieldUtils.getField(bean.getClass(), property, true); + if (isUseJPACopier(field)) { + properties.add(property); + } + } + return properties; + } + + /** + * Check if accessibleObject contains + * + * {@link javax.persistence.OneToMany#mappedBy()} + * {@link javax.persistence.OneToOne} + * + * @param accessibleObject + * method object + */ + private static boolean isUseJPACopier(AccessibleObject accessibleObject) { + if (accessibleObject == null) { + return false; + } + + if (accessibleObject.isAnnotationPresent(OneToOne.class)) { + return true; + } else if (accessibleObject.isAnnotationPresent(OneToMany.class) + && StringUtils.isNotEmpty( + accessibleObject.getAnnotation(OneToMany.class) + .mappedBy())) { + return true; + } + return false; + } +} diff --git a/zanata-model/src/main/java/org/zanata/util/ZanataMySQL5InnoDBDialect.java b/zanata-model/src/main/java/org/zanata/util/ZanataMySQL5InnoDBDialect.java deleted file mode 100644 index 5fc15aa571..0000000000 --- a/zanata-model/src/main/java/org/zanata/util/ZanataMySQL5InnoDBDialect.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.zanata.util; - -import java.sql.Types; - -import org.hibernate.dialect.MySQL5InnoDBDialect; - -public class ZanataMySQL5InnoDBDialect extends MySQL5InnoDBDialect { - - @Override - protected void registerVarcharTypes() { - registerColumnType(Types.VARCHAR, "longtext"); - // registerColumnType( Types.VARCHAR, 16777215, "mediumtext" ); - // registerColumnType( Types.VARCHAR, 65535, "text" ); - registerColumnType(Types.VARCHAR, 255, "varchar($l) binary"); - } - - @Override - public boolean areStringComparisonsCaseInsensitive() { - return false; - } - -} diff --git a/zanata-model/src/test/java/org/zanata/util/JPACopierTest.java b/zanata-model/src/test/java/org/zanata/util/JPACopierTest.java new file mode 100644 index 0000000000..491df95778 --- /dev/null +++ b/zanata-model/src/test/java/org/zanata/util/JPACopierTest.java @@ -0,0 +1,161 @@ +package org.zanata.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import org.junit.Test; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * @author Alex Eng aeng@redhat.com + */ +public class JPACopierTest { + @Test + public void testCopy() throws Exception { + ParentClass original = constructTestData(); + ParentClass clone = + JPACopier. copyBean(original, "customIgnoreField"); + assertClone(original, clone); + } + + private void assertClone(ParentClass original, ParentClass clone) { + assertThat(clone.getString()).isEqualTo(original.getString()); + + assertThat(clone.getCustomIgnoreField()).isNotEqualTo( + original.getCustomIgnoreField()); + + assertChildClass(original.getChild1(), clone.getChild1(), true); + assertChildClass(original.getChild2(), clone.getChild2(), false); + assertChildClass(original.getChild3(), clone.getChild3(), true); + } + + private void assertChildClass(ChildClass original, ChildClass clone, + boolean expectNewRef) { + if (expectNewRef) { + assertThat(clone).isNotSameAs(original); + assertThat(clone.getId()).isNotEqualTo(original.getId()); + assertThat(clone.getTestList()).isNotSameAs(original.getTestList()); + assertThat(clone.getTestSet()).isNotSameAs(original.getTestSet()); + assertThat(clone.getTestMap()).isNotSameAs(original.getTestMap()); + } else { + assertThat(clone.getId()).isEqualTo(original.getId()); + assertThat(clone.getTestList()).isSameAs(original.getTestList()); + assertThat(clone.getTestSet()).isSameAs(original.getTestSet()); + assertThat(clone.getTestMap()).isSameAs(original.getTestMap()); + } + + assertThat(clone.getTestString()).isEqualTo(original.getTestString()); + assertThat(clone.getTestList()).isEqualTo(original.getTestList()); + assertThat(clone.getTestSet()).isEqualTo(original.getTestSet()); + assertThat(clone.getTestMap()).isEqualTo(original.getTestMap()); + } + + private ParentClass constructTestData() { + List testList = Lists.newArrayList("list1", "list2", "list3"); + Set testSet = Sets.newHashSet("set1", "set2", "set3"); + Map testMap = Maps.newHashMap(); + testMap.put("One", "one"); + testMap.put("Two", "two"); + testMap.put("Three", "three"); + + ChildClass child1 = + new ChildClass(1L, "String1", testList, testSet, testMap); + + ChildClass child2 = + new ChildClass(2L, "String2", testList, testSet, testMap); + + ChildClass child3 = + new ChildClass(3L, "String3", testList, testSet, testMap); + + return new ParentClass("string", Boolean.TRUE, true, Byte.MIN_VALUE, + Byte.MAX_VALUE, Character.MIN_VALUE, + Character.MAX_VALUE, Double.MIN_VALUE, + Double.MAX_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, + Integer.MIN_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE, + Long.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, 100, + child1, child2, child3); + } + + @Setter + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ParentClass { + private String string; + + private Boolean wrapper_boolean; + private boolean primitive_boolean; + + private Byte wrapper_byte; + private byte primitive_byte; + + private Character wrapper_char; + private char primitive_char; + + private Double wrapper_double; + private double primitive_double; + + private Float wrapper_float; + private float primitive_float; + + private Integer wrapper_int; + private int primitive_int; + + private Long wrapper_long; + private long primitive_long; + + private Short wrapper_short; + private short primitive_short; + + // custom ignore field + private int customIgnoreField; + + // expect to copy with new reference + @OneToOne + private ChildClass child1; + + // expect to copy with same reference + @OneToMany + private ChildClass child2; + + // expect to copy with new reference + @OneToMany(mappedBy = "id") + private ChildClass child3; + + } + + @Setter + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ChildClass { + // common ignored field + private Long id; + + private String testString; + + // expect to create new instance when copy + private List testList; + + // expect to create new instance when copy + private Set testSet; + + // expect to create new instance when copy + private Map testMap; + } + +} diff --git a/zanata-war/pom.xml b/zanata-war/pom.xml index 3bc2fb35c6..75a5ba4fd5 100644 --- a/zanata-war/pom.xml +++ b/zanata-war/pom.xml @@ -4,7 +4,7 @@ org.zanata server - 3.4.3-SNAPSHOT + 3.5.0-SNAPSHOT zanata-war war @@ -15,7 +15,6 @@ scm:git:git://github.com/zanata/zanata.git scm:git:git@github.com:zanata/zanata.git https://github.com/zanata/zanata - HEAD @@ -124,7 +123,6 @@ - true javax.xml.bind:jaxb-api @@ -136,49 +134,53 @@ org.jboss.resteasy:resteasy-multipart-provider com.google.protobuf:protobuf-java - - com.google.code.findbugs:jsr305 com.lowagie:itext org.jboss.as:jboss-as-controller - - org.json:json - + com.googlecode.log4jdbc:log4jdbc - - - + antlr:antlr + com.google.guava:guava-gwt - com.ibm.icu:icu4j - com.sun.faces:jsf-impl - commons-codec:commons-codec - commons-collections:commons-collections - commons-lang:commons-lang + + javax.el:el-api javax.servlet.jsp:jsp-api - mysql:mysql-connector-java + com.sun.faces:jsf-impl + org.apache.solr:solr-core org.apache.solr:solr-solrj - org.codehaus.jackson:jackson-xc + org.drools:drools-compiler + org.antlr:antlr + + org.hibernate.common:hibernate-commons-annotations + org.hibernate:hibernate-ehcache org.hibernate:hibernate-search-analyzers org.hibernate:hibernate-search + org.hibernate:hibernate-testing - org.htmlparser:htmlparser org.jboss.arquillian.junit:arquillian-junit-container org.jboss.arquillian.protocol:arquillian-protocol-servlet org.jboss.as:jboss-as-arquillian-container-managed + org.jboss.resteasy:resteasy-jackson-provider + org.codehaus.jackson:jackson-xc + org.jboss.seam:jboss-seam-debug + org.jboss.seam:jboss-seam-mail - org.openxri:openxri-client - org.openxri:openxri-syntax - org.richfaces.core:richfaces-core-impl + + org.jvnet.mock-javamail:mock-javamail + org.tuckey:urlrewritefilter - org.zanata:zanata-rest-client + + ${jdbc.groupId}:${jdbc.artifactId} + + dom4j:dom4j @@ -203,53 +205,46 @@ + + + + + com.ning.maven.plugins + maven-duplicate-finder-plugin - - - - - - - - com.google.common.* - com.google.gwt.* - com.google.web.bindery.* - com.ibm.icu.* - com.steadystate.css.* - javax.annotation.* - javax.servlet.* - javax.servlet.jsp.* - javax.validation.ConstraintViolationException_CustomFieldSerializer - javax.xml.* - org.apache.commons.beanutils.* - org.apache.commons.codec.* - org.apache.commons.collections.* - org.apache.commons.io.* - org.apache.commons.lang.* - org.apache.commons.logging.* - org.apache.html.* - org.apache.http.* - org.apache.james.mime4j.* - org.apache.regexp.* - org.apache.wml.* - org.apache.xerces.* - org.apache.xml.* - org.apache.xmlcommons.Version - org.cyberneko.html.* - org.hibernate.validator.* - org.w3c.css.sac.* - org.w3c.dom.* - org.xml.sax.* - - - org.osgi.util.* - - com.sun.tools.* - sun.* - - - + + + com.google.gwt + gwt-user + + + + + com/lowagie/text/pdf/fonts/cmap_info.txt + + META-INF/components.xml + + META-INF/faces-config.xml + + META-INF/javamail.providers + + META-INF/richfaces/resource-mappings.properties + + META-INF/seam-deployment.properties + + build.properties + + seam.properties + + + + validate + + check + + + @@ -444,7 +439,6 @@ maven-surefire-plugin - 2.16 -Dconcordion.output.dir=${concordion.output.dir} none:none @@ -1074,12 +1068,23 @@ + + org.apache.velocity + velocity + 1.7 + + org.assertj assertj-core test + + com.googlecode.totallylazy + totallylazy + 1.10 + @@ -1123,12 +1128,6 @@ zanata-rest-client test - - org.zanata - zanata-rest-client - test-jar - test - @@ -1140,12 +1139,6 @@ - - com.google.gwt - gwt-dev - provided - - com.google.gwt gwt-servlet @@ -1158,11 +1151,26 @@ provided + + com.google.gwt.gwtmockito + gwtmockito + 1.1.2 + + + com.google.gwt + gwt-dev + + + org.mockito + mockito-all + + + + org.json json 20090211 - provided @@ -1185,9 +1193,9 @@ - org.jboss.seam jboss-seam-debug + test @@ -1204,11 +1212,16 @@ org.jboss.resteasy resteasy-jaxrs + ${resteasy.scope} javassist javassist + + javax.annotation + jsr250-api + jcip-annotations net.jcip @@ -1218,15 +1231,18 @@ org.jboss.resteasy resteasy-jaxb-provider + ${resteasy.scope} org.jboss.resteasy resteasy-jackson-provider + ${resteasy.scope} org.jboss.resteasy resteasy-multipart-provider + ${resteasy.scope} @@ -1254,10 +1270,12 @@ org.jboss.spec.javax.faces jboss-jsf-api_2.1_spec + provided org.jboss.spec.javax.transaction jboss-transaction-api_1.1_spec + provided org.jboss @@ -1283,9 +1301,55 @@ ecj org.eclipse.jdt.core.compiler + + org.antlr + antlr + + + antlr + antlr + + + org.antlr + antlr + 3.3 + provided + + + + antlr + antlr + provided + + + + dom4j + dom4j + provided + + + + com.googlecode.owasp-java-html-sanitizer + owasp-java-html-sanitizer + r239 + + + com.google.code.findbugs + jsr305 + + + + + + org.jvnet.mock-javamail + mock-javamail + 1.9 + test + + @@ -1296,7 +1360,6 @@ org.richfaces.ui richfaces-components-ui - org.richfaces.core richfaces-core-impl @@ -1306,6 +1369,7 @@ com.sun.faces jsf-impl + provided @@ -1365,6 +1429,12 @@ test + + net.htmlparser.jericho + jericho-html + 3.3 + + net.sf.ehcache ehcache-core @@ -1393,6 +1463,10 @@ net.sf.okapi.filters okapi-filter-plaintext + + net.sf.okapi.filters + okapi-filter-regex + net.sf.okapi @@ -1445,20 +1519,22 @@ com.google.guava guava-gwt + + + com.google.code.findbugs + jsr305 + + com.google.code.findbugs annotations - - com.google.code.findbugs - jsr305 - net.bull.javamelody javamelody-core - 1.48.0 + 1.52.0 @@ -1529,7 +1605,11 @@ - + + org.hibernate.common + hibernate-commons-annotations + provided + org.hibernate hibernate-search-analyzers @@ -1555,8 +1635,8 @@ - javax.servlet - javax.servlet-api + org.jboss.spec.javax.servlet + jboss-servlet-api_3.0_spec provided @@ -1592,8 +1672,14 @@ - javax.annotation - jsr250-api + javax.activation + activation + provided + + + + org.jboss.spec.javax.annotation + jboss-annotations-api_1.1_spec provided @@ -1626,12 +1712,14 @@ com.h2database h2 + 1.3.176 provided org.javassist javassist + ${hibernate.scope} @@ -1658,15 +1746,6 @@ test - - - org.jboss.arquillian.config arquillian-config-api @@ -1764,6 +1843,7 @@ org.jboss.logging jboss-logging + 3.1.3.GA test @@ -1906,20 +1986,16 @@ 3.0.2.Final - - org.htmlparser - htmlparser - 1.6 - - - - tools - com.sun - - + org.apache.httpcomponents + httpcore + + + org.apache.httpcomponents + httpclient + org.openid4java openid4java @@ -1936,60 +2012,16 @@ - - org.openxri - openxri-client - 1.2.0 - - - xalan - xalan - - - xerces - xercesImpl - - - org.slf4j - slf4j-jcl - - - commons-logging - commons-logging - - - - - - org.openxri - openxri-syntax - 1.2.0 - - - org.slf4j - slf4j-jcl - - - commons-logging - commons-logging - - - - org.picketbox picketbox - 4.0.14.Final + 4.0.15.Final + provided javax.validation validation-api - - - - antlr - antlr provided @@ -1998,6 +2030,10 @@ classloader-leak-prevention 1.9.3 + + javax.servlet + servlet-api + org.apache.cxf cxf-rt-transports-http @@ -2018,7 +2054,8 @@ com.beust jcommander - 1.12 + 1.27 + provided commons-io @@ -2032,7 +2069,7 @@ org.jboss.resteasy jaxrs-api - provided + ${resteasy.scope} javax.xml.bind diff --git a/zanata-war/src/etc/graphics.svg b/zanata-war/src/etc/graphics.svg deleted file mode 100644 index 5994c25474..0000000000 --- a/zanata-war/src/etc/graphics.svg +++ /dev/null @@ -1,1573 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - TableEditor row backgrounds Fuzzy Translated New - - - - - - - - - Normal Filtered - Untranslated / New - Need Review - Approved - Side panel background Border - - - - - - - - - Flies - - - - - - - - - - - - - - - - - - - - - - diff --git a/zanata-war/src/etc/mysql.properties b/zanata-war/src/etc/mysql.properties index 6779c989ea..ae17fa49c6 100644 --- a/zanata-war/src/etc/mysql.properties +++ b/zanata-war/src/etc/mysql.properties @@ -1,5 +1,4 @@ ds.jndi.name=zanataDatasource -ds.hibernate.dialect=org.zanata.ZanataMySQL5InnoDBDialect ds.driver.class=com.mysql.jdbc.Driver ds.connection.url=jdbc:mysql://localhost:3306/zanata?characterEncoding=UTF-8 ds.user.name=sa diff --git a/zanata-war/src/main/java/org/zanata/ApplicationConfiguration.java b/zanata-war/src/main/java/org/zanata/ApplicationConfiguration.java index 135237c9ef..ecc08dae81 100644 --- a/zanata-war/src/main/java/org/zanata/ApplicationConfiguration.java +++ b/zanata-war/src/main/java/org/zanata/ApplicationConfiguration.java @@ -75,6 +75,9 @@ public class ApplicationConfiguration implements Serializable { private static final String STYLESHEET_LOCAL_PATH = "/assets/css/style.min.css"; + @Getter + private static final int defaultMaxFilesPerUpload = 100; + @In private DatabaseBackedConfig databaseBackedConfig; @In @@ -430,20 +433,25 @@ private String getBaseWebAssetsUrl() { } public int getMaxConcurrentRequestsPerApiKey() { - String max = - databaseBackedConfig.getMaxConcurrentRequestsPerApiKey(); - if (Strings.isNullOrEmpty(max)) { - return 6; - } - return Integer.parseInt(max); + return parseIntegerOrDefault(databaseBackedConfig.getMaxConcurrentRequestsPerApiKey(), 6); } public int getMaxActiveRequestsPerApiKey() { - String max = - databaseBackedConfig.getMaxActiveRequestsPerApiKey(); - if (Strings.isNullOrEmpty(max)) { - return 2; + return parseIntegerOrDefault(databaseBackedConfig.getMaxActiveRequestsPerApiKey(), 2); + } + + public int getMaxFilesPerUpload() { + return parseIntegerOrDefault(databaseBackedConfig.getMaxFilesPerUpload(), defaultMaxFilesPerUpload); + } + + private int parseIntegerOrDefault(String value, int defaultValue) { + if (Strings.isNullOrEmpty(value)) { + return defaultValue; + } + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; } - return Integer.parseInt(max); } } diff --git a/zanata-war/src/main/java/org/zanata/ZanataInit.java b/zanata-war/src/main/java/org/zanata/ZanataInit.java index 46290d9789..29aba9ec93 100644 --- a/zanata-war/src/main/java/org/zanata/ZanataInit.java +++ b/zanata-war/src/main/java/org/zanata/ZanataInit.java @@ -38,6 +38,7 @@ import javax.naming.NamingException; import javax.servlet.ServletContext; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; @@ -52,8 +53,6 @@ import org.zanata.rest.dto.VersionInfo; import org.zanata.util.VersionUtility; -import com.beust.jcommander.internal.Lists; - /** * Doesn't do much useful stuff except printing a log message and firing the * "Zanata.startup" event. diff --git a/zanata-war/src/main/java/org/zanata/action/AbstractProfileAction.java b/zanata-war/src/main/java/org/zanata/action/AbstractProfileAction.java index 03fa906fee..57670497c6 100644 --- a/zanata-war/src/main/java/org/zanata/action/AbstractProfileAction.java +++ b/zanata-war/src/main/java/org/zanata/action/AbstractProfileAction.java @@ -6,14 +6,12 @@ import org.hibernate.validator.constraints.NotEmpty; import org.jboss.seam.annotations.In; import org.jboss.seam.faces.FacesMessages; -import org.jboss.seam.faces.Renderer; import org.jboss.seam.security.management.JpaIdentityStore; import org.zanata.dao.AccountDAO; import org.zanata.dao.PersonDAO; import org.zanata.model.HAccount; import org.zanata.model.HPerson; import org.zanata.security.ZanataIdentity; -import com.google.common.base.Strings; /** * @author Patrick Huang @@ -26,9 +24,6 @@ public abstract class AbstractProfileAction { protected boolean valid; private String activationKey; - @In(create = true) - protected Renderer renderer; - @In ZanataIdentity identity; diff --git a/zanata-war/src/main/java/org/zanata/action/AccountMergeAction.java b/zanata-war/src/main/java/org/zanata/action/AccountMergeAction.java index 2d54aea053..d7f445a7fa 100644 --- a/zanata-war/src/main/java/org/zanata/action/AccountMergeAction.java +++ b/zanata-war/src/main/java/org/zanata/action/AccountMergeAction.java @@ -27,7 +27,6 @@ import lombok.Getter; import lombok.Setter; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; @@ -39,10 +38,13 @@ import org.zanata.dao.AccountDAO; import org.zanata.model.HAccount; import org.zanata.security.AuthenticationManager; +import org.zanata.security.AuthenticationType; +import org.zanata.security.ZanataCredentials; import org.zanata.security.openid.OpenIdAuthCallback; import org.zanata.security.openid.OpenIdAuthenticationResult; import org.zanata.security.openid.OpenIdProviderType; import org.zanata.service.RegisterService; +import org.zanata.util.ServiceLocator; /** * @author Carlos Munoz ruleActions = getRuleActionsList(); public HCopyTransOptions getInstance() { if (instance == null) { @@ -110,23 +112,25 @@ public void update(String action, String value) { } } - @CachedMethodResult - public List getRuleActions() { - List list = Lists.newArrayList(); - list.add(new RuleAction(HCopyTransOptions.ConditionRuleAction.IGNORE, - "button--success", zanataMessages - .getMessage("jsf.iteration.CopyTrans.Action.continue"))); - - list.add(new RuleAction( - HCopyTransOptions.ConditionRuleAction.DOWNGRADE_TO_FUZZY, - "button--unsure", - zanataMessages - .getMessage("jsf.iteration.CopyTrans.Action.downgradeToFuzzy"))); - - list.add(new RuleAction(HCopyTransOptions.ConditionRuleAction.REJECT, - "button--danger", zanataMessages - .getMessage("jsf.iteration.CopyTrans.Action.reject"))); - return list; + private List getRuleActionsList() { + return Lists + .newArrayList( + new RuleAction( + HCopyTransOptions.ConditionRuleAction.IGNORE, + "button--success", + msgs.get( + "jsf.iteration.CopyTrans.Action.continue")), + new RuleAction( + HCopyTransOptions.ConditionRuleAction.DOWNGRADE_TO_FUZZY, + "button--unsure", + msgs.get( + "jsf.iteration.CopyTrans.Action.downgradeToFuzzy")), + new RuleAction( + HCopyTransOptions.ConditionRuleAction.REJECT, + "button--danger", + msgs.get( + "jsf.iteration.CopyTrans.Action.reject")) + ); } public void save() { diff --git a/zanata-war/src/main/java/org/zanata/action/CopyVersionManager.java b/zanata-war/src/main/java/org/zanata/action/CopyVersionManager.java new file mode 100644 index 0000000000..5afe0fea2b --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/action/CopyVersionManager.java @@ -0,0 +1,78 @@ +package org.zanata.action; + +import static org.zanata.async.tasks.CopyVersionTask.CopyVersionTaskHandle; + +import java.io.Serializable; + +import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.In; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; +import org.jboss.seam.security.Identity; +import org.zanata.async.tasks.CopyVersionTask; +import org.zanata.service.AsyncTaskManagerService; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Alex Eng aeng@redhat.com + */ +@AutoCreate +@Name("copyVersionManager") +@Scope(ScopeType.STATELESS) +@Slf4j +public class CopyVersionManager implements Serializable { + @In + private AsyncTaskManagerService asyncTaskManagerServiceImpl; + + @In + private Identity identity; + + public void startCopyVersion(String projectSlug, String versionSlug, + String newVersionSlug) { + asyncTaskManagerServiceImpl.startTask(new CopyVersionTask( + projectSlug, versionSlug, newVersionSlug), + CopyVersionKey.getKey(projectSlug, newVersionSlug)); + } + + public void cancelCopyVersion(String projectSlug, String versionSlug) { + if (isCopyVersionRunning(projectSlug, versionSlug)) { + CopyVersionTaskHandle handle = + getCopyVersionProcessHandle(projectSlug, versionSlug); + handle.forceCancel(); + handle.setCancelledTime(System.currentTimeMillis()); + handle.setCancelledBy(identity.getCredentials().getUsername()); + + log.info("Copy version cancelled- {}:{}", projectSlug, versionSlug); + } + } + + public CopyVersionTask.CopyVersionTaskHandle getCopyVersionProcessHandle( + String projectSlug, String versionSlug) { + return (CopyVersionTask.CopyVersionTaskHandle) asyncTaskManagerServiceImpl + .getHandleByKey(CopyVersionKey.getKey(projectSlug, versionSlug)); + } + + public boolean isCopyVersionRunning(String projectSlug, String versionSlug) { + CopyVersionTaskHandle handle = + getCopyVersionProcessHandle(projectSlug, versionSlug); + return handle != null && !handle.isDone(); + } + + @EqualsAndHashCode + @Getter + @AllArgsConstructor + public static final class CopyVersionKey implements Serializable { + private final String projectSlug; + private final String versionSlug; + + public static CopyVersionKey getKey(String projectSlug, + String versionSlug) { + return new CopyVersionKey(projectSlug, versionSlug); + } + } +} diff --git a/zanata-war/src/main/java/org/zanata/action/DashboardAction.java b/zanata-war/src/main/java/org/zanata/action/DashboardAction.java index 2aff46cffb..39ffabd566 100644 --- a/zanata-war/src/main/java/org/zanata/action/DashboardAction.java +++ b/zanata-war/src/main/java/org/zanata/action/DashboardAction.java @@ -30,23 +30,20 @@ import com.google.common.collect.Collections2; import lombok.NonNull; import org.apache.commons.lang.StringUtils; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.security.Restrict; import org.jboss.seam.security.management.JpaIdentityStore; -import org.zanata.annotation.CachedMethodResult; import org.zanata.common.EntityStatus; import org.zanata.dao.AccountDAO; import org.zanata.dao.ProjectDAO; -import org.zanata.dao.ProjectIterationDAO; +import org.zanata.i18n.Messages; import org.zanata.model.HAccount; import org.zanata.model.HLocale; import org.zanata.model.HPerson; import org.zanata.model.HProject; -import org.zanata.model.HProjectIteration; import org.zanata.security.ZanataIdentity; import org.zanata.service.ActivityService; import org.zanata.service.GravatarService; @@ -55,19 +52,17 @@ import org.zanata.service.LanguageTeamService; import org.zanata.util.DateUtil; import org.zanata.util.ServiceLocator; -import org.zanata.util.StringUtil; -import org.zanata.util.UrlUtil; import javax.annotation.Nullable; import lombok.Getter; -import org.zanata.util.ZanataMessages; @Name("dashboardAction") @Scope(ScopeType.PAGE) @Restrict("#{identity.loggedIn}") public class DashboardAction implements Serializable { private static final long serialVersionUID = 1L; + private static final int USER_IMAGE_SIZE = 115; @In private GravatarService gravatarServiceImpl; @@ -88,7 +83,7 @@ public class DashboardAction implements Serializable { private ZanataIdentity identity; @In - private ZanataMessages zanataMessages; + private Messages msgs; @In(required = false, value = JpaIdentityStore.AUTHENTICATED_USER) private HAccount authenticatedAccount; @@ -96,7 +91,13 @@ public class DashboardAction implements Serializable { @Getter private ProjectFilter projectList = new ProjectFilter(); - private static final int USER_IMAGE_SIZE = 115; + @Getter(lazy = true) + private final int userMaintainedProjectsCount = + countUserMaintainedProjects(); + + @Getter(lazy = true) + private final List userMaintainedProjects = + fetchUserMaintainedProjects(); public String getUserImageUrl() { return gravatarServiceImpl.getUserImageUrl(USER_IMAGE_SIZE); @@ -125,13 +126,11 @@ public Object apply(@NonNull HLocale locale) { ", "); } - @CachedMethodResult - public int getUserMaintainedProjectsCount() { + private int countUserMaintainedProjects() { return authenticatedAccount.getPerson().getMaintainerProjects().size(); } - @CachedMethodResult - public List getUserMaintainedProjects() { + private List fetchUserMaintainedProjects() { List sortedList = new ArrayList(); if (canViewObsolete()) { @@ -162,7 +161,6 @@ public String getLastTranslatedTime(HProject project) { return DateUtil.formatShortDate(project.getLastChanged()); } - @CachedMethodResult public boolean canViewObsolete() { return identity != null && identity.hasPermission("HProject", "view-obsolete"); @@ -206,9 +204,9 @@ public String getLastTranslatorMessage(HProject project) { else { username = lastTrans.getName(); } - return zanataMessages.getMessage( - "jsf.dashboard.activity.lastTranslatedBy.message", - username); + return msgs + .format("jsf.dashboard.activity.lastTranslatedBy.message", + username); } return ""; } diff --git a/zanata-war/src/main/java/org/zanata/action/GlossaryAction.java b/zanata-war/src/main/java/org/zanata/action/GlossaryAction.java index 1578a5b011..0c224bcdaa 100644 --- a/zanata-war/src/main/java/org/zanata/action/GlossaryAction.java +++ b/zanata-war/src/main/java/org/zanata/action/GlossaryAction.java @@ -2,17 +2,14 @@ import java.io.InputStream; import java.io.Serializable; -import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; - import javax.faces.context.FacesContext; import javax.validation.ConstraintViolationException; -import lombok.extern.slf4j.Slf4j; - import org.apache.commons.lang.StringUtils; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; @@ -20,18 +17,26 @@ import org.jboss.seam.annotations.Scope; import org.jboss.seam.faces.FacesMessages; import org.jboss.seam.international.StatusMessage.Severity; -import org.zanata.annotation.CachedMethods; import org.zanata.common.LocaleId; import org.zanata.dao.GlossaryDAO; import org.zanata.dao.LocaleDAO; import org.zanata.exception.ZanataServiceException; +import org.zanata.i18n.Messages; import org.zanata.model.HLocale; import org.zanata.rest.dto.Glossary; import org.zanata.service.GlossaryFileService; +import org.zanata.ui.AbstractListFilter; +import org.zanata.ui.InMemoryListFilter; +import org.zanata.util.ServiceLocator; +import com.google.common.collect.Lists; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; @Name("glossaryAction") @Scope(ScopeType.PAGE) -@CachedMethods @Slf4j public class GlossaryAction implements Serializable { private static final long serialVersionUID = 1L; @@ -45,31 +50,41 @@ public class GlossaryAction implements Serializable { @In private GlossaryFileService glossaryFileServiceImpl; - private GlossaryFileUploadHelper glossaryFileUpload; + @In + private Messages msgs; - private String localeToDelete; + @Getter + private GlossaryFileUploadHelper glossaryFileUpload = + new GlossaryFileUploadHelper(); - public void initialize() { - glossaryFileUpload = new GlossaryFileUploadHelper(); + private List glossaryEntries; + + @Getter + private SortingType glossarySortingList = new SortingType( + Lists.newArrayList(SortingType.SortOption.ALPHABETICAL, + SortingType.SortOption.Entry)); + + private final GlossaryEntryComparator glossaryEntryComparator = + new GlossaryEntryComparator( + getGlossarySortingList()); + + public String getDeleteConfirmationMessage(String localeId) { + return msgs.format("jsf.Glossary.delete.confirm", localeId); } public List getAvailableLocales() { return localeDAO.findAllActive(); } - public GlossaryFileUploadHelper getGlossaryFileUpload() { - return glossaryFileUpload; - } - - public String delete() { + public String deleteGlossary(String localeId) { int rowCount = 0; - if (StringUtils.isNotEmpty(localeToDelete)) { + if (StringUtils.isNotEmpty(localeId)) { rowCount = - glossaryDAO.deleteAllEntries(new LocaleId(localeToDelete)); - log.info("Glossary deleted (" + localeToDelete + "): " + rowCount); + glossaryDAO.deleteAllEntries(new LocaleId(localeId)); + log.info("Glossary deleted (" + localeId + "): " + rowCount); } - FacesMessages.instance().add(Severity.INFO, "Glossary deleted: {0}", - rowCount); + FacesMessages.instance().add(Severity.INFO, + msgs.format("jsf.Glossary.deleted", rowCount, localeId)); return FacesContext.getCurrentInstance().getViewRoot().getViewId(); } @@ -104,27 +119,35 @@ public String uploadFile() { return FacesContext.getCurrentInstance().getViewRoot().getViewId(); } - public List getStats() { - List result = new ArrayList(); - - Map statsMap = - glossaryDAO.getGlossaryTermCountByLocale(); - - for (Entry entry : statsMap.entrySet()) { - result.add(new Status(entry.getKey().getLocaleId().getId(), entry - .getKey().retrieveDisplayName(), entry.getValue())); - } - - Collections.sort(result); - return result; + /** + * Sort glossary entry list + */ + public void sortGlossaryEntries() { + Collections.sort(getEntries(), glossaryEntryComparator); + glossaryFilter.reset(); } - public String getLocaleToDelete() { - return localeToDelete; + public List getEntries() { + if (glossaryEntries == null) { + glossaryEntries = Lists.newArrayList(); + Map statsMap = + glossaryDAO.getGlossaryTermCountByLocale(); + for (Entry entry : statsMap.entrySet()) { + glossaryEntries.add( + new GlossaryEntry(entry.getKey().getLocaleId().getId(), + entry + .getKey().retrieveDisplayName(), + entry.getValue())); + } + } + return glossaryEntries; } - public void setLocaleToDelete(String localeToDelete) { - this.localeToDelete = localeToDelete; + private List getEntries(GlossaryDAO glossaryDAO) { + if (this.glossaryDAO == null) { + this.glossaryDAO = glossaryDAO; + } + return getEntries(); } /** @@ -132,123 +155,116 @@ public void setLocaleToDelete(String localeToDelete) { */ public static class GlossaryFileUploadHelper implements Serializable { private static final long serialVersionUID = 1L; + + @Getter + @Setter private InputStream fileContents; + + @Getter + @Setter private String fileName; + + @Getter + @Setter private String sourceLang = "en-US"; + + @Getter + @Setter private String transLang; + + @Getter + @Setter private boolean treatSourceCommentsAsTarget = false; - private String commentCols = "pos,description"; - public InputStream getFileContents() { - return fileContents; - } + @Getter + @Setter + private String commentCols = "pos,description"; public LocaleId getTransLocaleId() { - if (StringUtils.isNotEmpty(getTransLang())) { - return new LocaleId(getTransLang()); - } - return null; + return getLocaleId(getTransLang()); } public LocaleId getSourceLocaleId() { - if (StringUtils.isNotEmpty(getSourceLang())) { - return new LocaleId(getSourceLang()); - } - return null; + return getLocaleId(getSourceLang()); } - public void setFileContents(InputStream fileContents) { - this.fileContents = fileContents; - } - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - - public String getSourceLang() { - return sourceLang; - } - - public void setSourceLang(String sourceLang) { - this.sourceLang = sourceLang; - } - - public String getTransLang() { - return transLang; - } - - public void setTransLang(String transLang) { - this.transLang = transLang; + private LocaleId getLocaleId(String lang) { + if (StringUtils.isNotEmpty(lang)) { + return new LocaleId(lang); + } + return null; } - public boolean isTreatSourceCommentsAsTarget() { - return treatSourceCommentsAsTarget; + public List getCommentColsList() { + String[] commentHeadersList = + StringUtils.split(getCommentCols(), ","); + return Lists.newArrayList(commentHeadersList); } + } - public void setTreatSourceCommentsAsTarget( - boolean treatSourceCommentsAsTarget) { - this.treatSourceCommentsAsTarget = treatSourceCommentsAsTarget; - } + private class GlossaryEntryComparator implements Comparator { + private SortingType sortingType; - public String getCommentCols() { - return commentCols; + public GlossaryEntryComparator(SortingType sortingType) { + this.sortingType = sortingType; } - public void setCommentCols(String commentCols) { - this.commentCols = commentCols; - } + @Override + public int compare(GlossaryEntry entry1, GlossaryEntry entry2) { + SortingType.SortOption selectedSortOption = + sortingType.getSelectedSortOption(); + + if (!selectedSortOption.isAscending()) { + GlossaryEntry temp = entry1; + entry1 = entry2; + entry2 = temp; + } - public List getCommentColsList() { - String[] commentHeadersList = - StringUtils.split(getCommentCols(), ","); - List list = new ArrayList(); - if (commentHeadersList != null && commentHeadersList.length > 0) { - Collections.addAll(list, commentHeadersList); + if (selectedSortOption.equals(SortingType.SortOption.ALPHABETICAL)) { + return entry1.getDisplayName().compareTo( + entry2.getDisplayName()); + } else if (selectedSortOption.equals(SortingType.SortOption.Entry)) { + return entry1.getEntryCount() > entry2.getEntryCount() ? 1 : -1; } - return list; + + return 0; } } /** - * Glossary status class + * Glossary entry class * * @author Alex Eng aeng@redhat.com * */ - public static class Status implements Comparable, Serializable { - private static final long serialVersionUID = 1L; + @AllArgsConstructor + public class GlossaryEntry implements Serializable { + @Getter private String localeId; + @Getter + private String displayName; + @Getter private int entryCount; - private String name; - - public Status(String localeId, String name, int entryCount) { - this.localeId = localeId; - this.entryCount = entryCount; - this.name = name; - } - - public String getLocaleId() { - return localeId; - } - - public int getEntryCount() { - return entryCount; - } - - public String getName() { - return name; - } - - @Override - public int compareTo(Status o) { - if (o.getEntryCount() == this.getEntryCount()) { - return 0; - } - return o.getEntryCount() > this.getEntryCount() ? 1 : -1; - } } + + @Getter + private final AbstractListFilter glossaryFilter = + new InMemoryListFilter() { + private GlossaryDAO glossaryDAO = ServiceLocator.instance() + .getInstance(GlossaryDAO.class); + + @Override + protected List fetchAll() { + return getEntries(glossaryDAO); + } + + @Override + protected boolean include(GlossaryEntry elem, + String filter) { + return StringUtils.containsIgnoreCase(elem.getLocaleId(), + filter) + || StringUtils.containsIgnoreCase( + elem.getDisplayName(), filter); + } + }; } diff --git a/zanata-war/src/main/java/org/zanata/action/InactiveAccountAction.java b/zanata-war/src/main/java/org/zanata/action/InactiveAccountAction.java index 312e35c81d..7b55becfef 100644 --- a/zanata-war/src/main/java/org/zanata/action/InactiveAccountAction.java +++ b/zanata-war/src/main/java/org/zanata/action/InactiveAccountAction.java @@ -75,10 +75,9 @@ public void sendActivationEmail() { String message = emailServiceImpl.sendActivationEmail( - EmailService.ACTIVATION_ACCOUNT_EMAIL_TEMPLATE, account - .getPerson().getName(), account.getPerson() - .getEmail(), account.getAccountActivationKey() - .getKeyHash()); + account.getPerson().getName(), + account.getPerson().getEmail(), + account.getAccountActivationKey().getKeyHash()); FacesMessages.instance().add(message); } @@ -103,7 +102,7 @@ public String changeEmail() { private boolean validateEmail(String email) { if (StringUtils.isEmpty(email)) { FacesMessages.instance().addToControl("email", - "#{messages['javax.faces.component.UIInput.REQUIRED']}"); + "#{msgs['javax.faces.component.UIInput.REQUIRED']}"); return false; } diff --git a/zanata-war/src/main/java/org/zanata/action/LanguageJoinUpdateRoleAction.java b/zanata-war/src/main/java/org/zanata/action/LanguageJoinUpdateRoleAction.java index 9488fc5e46..cf41de339d 100644 --- a/zanata-war/src/main/java/org/zanata/action/LanguageJoinUpdateRoleAction.java +++ b/zanata-war/src/main/java/org/zanata/action/LanguageJoinUpdateRoleAction.java @@ -26,21 +26,22 @@ import lombok.Setter; import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.security.management.JpaIdentityStore; -import org.zanata.annotation.CachedMethodResult; import org.zanata.common.LocaleId; import org.zanata.dao.LocaleMemberDAO; +import org.zanata.i18n.Messages; import org.zanata.model.HAccount; import org.zanata.model.HLocaleMember; -import org.zanata.util.ZanataMessages; /** * @author Alex Eng aeng@redhat.com */ +@AutoCreate @Name("languageJoinUpdateRoleAction") @Scope(ScopeType.PAGE) public class LanguageJoinUpdateRoleAction implements Serializable { @@ -52,7 +53,9 @@ public class LanguageJoinUpdateRoleAction implements Serializable { "request_role_language"; @In - private ZanataMessages zanataMessages; + private SendEmailAction sendEmail; + @In + private Messages msgs; @In private LocaleMemberDAO localeMemberDAO; @@ -91,10 +94,14 @@ public boolean hasRoleRequest() { public String getSubject() { if (emailType.equals(EMAIL_TYPE_REQUEST_JOIN)) { subject = - zanataMessages.getMessage("jsf.email.joinrequest.Subject"); + msgs.format("jsf.email.joinrequest.Subject", + sendEmail.getFromLoginName(), + sendEmail.getLocale().getLocaleId().getId()); } else { subject = - zanataMessages.getMessage("jsf.email.rolerequest.Subject"); + msgs.format("jsf.email.rolerequest.Subject", + sendEmail.getFromLoginName(), + sendEmail.getLocale().getLocaleId().getId()); } return subject; } @@ -102,16 +109,22 @@ public String getSubject() { public String getTitle() { if (emailType.equals(EMAIL_TYPE_REQUEST_JOIN)) { title = - zanataMessages - .getMessage("jsf.RequestToJoinLanguageTeamTitle"); + msgs + .format("jsf.RequestToJoinLanguageTeamTitle", + sendEmail.getLocale().getLocaleId().getId()); } else { title = - zanataMessages - .getMessage("jsf.RequestRoleLanguageTeamTitle"); + msgs + .format("jsf.RequestRoleLanguageTeamTitle", + sendEmail.getLocale().getLocaleId().getId()); } return title; } + public boolean requestingTranslator() { + return requestAsTranslator != null && requestAsTranslator && !isTranslator(); + } + public boolean isTranslator() { HLocaleMember member = getLocaleMember(); if (member != null) { @@ -120,6 +133,10 @@ public boolean isTranslator() { return false; } + public boolean requestingReviewer() { + return requestAsReviewer != null && requestAsReviewer && !isReviewer(); + } + public boolean isReviewer() { HLocaleMember member = getLocaleMember(); if (member != null) { @@ -128,6 +145,10 @@ public boolean isReviewer() { return false; } + public boolean requestingCoordinator() { + return requestAsCoordinator != null && requestAsCoordinator && !isCoordinator(); + } + public boolean isCoordinator() { HLocaleMember member = getLocaleMember(); if (member != null) { @@ -136,7 +157,6 @@ public boolean isCoordinator() { return false; } - @CachedMethodResult private HLocaleMember getLocaleMember() { return localeMemberDAO.findByPersonAndLocale(authenticatedAccount .getPerson().getId(), new LocaleId(language)); diff --git a/zanata-war/src/main/java/org/zanata/action/LanguageManagerAction.java b/zanata-war/src/main/java/org/zanata/action/LanguageManagerAction.java index f970dc96e2..0810d87387 100644 --- a/zanata-war/src/main/java/org/zanata/action/LanguageManagerAction.java +++ b/zanata-war/src/main/java/org/zanata/action/LanguageManagerAction.java @@ -61,7 +61,7 @@ public class LanguageManagerAction implements Serializable { private ResourceUtils resourceUtils; @In - private Map messages; + private Map msgs; private String language; @@ -176,7 +176,7 @@ public boolean isLanguageNameValid() { if (language.length() > LENGTH_LIMIT) { this.uLocale = null; this.languageNameValidationMessage = - messages.get("jsf.language.validation.Invalid"); + msgs.get("jsf.language.validation.Invalid"); return false; } @@ -190,28 +190,28 @@ public boolean isLanguageNameValid() { localeId = new LocaleId(language); } catch (IllegalArgumentException iaex) { this.languageNameValidationMessage = - messages.get("jsf.language.validation.Invalid"); + msgs.get("jsf.language.validation.Invalid"); return false; } // check for already registered languages if (localeServiceImpl.localeExists(localeId)) { this.languageNameValidationMessage = - messages.get("jsf.language.validation.Existing"); + msgs.get("jsf.language.validation.Existing"); return false; } // Check for plural forms if (resourceUtils.getPluralForms(localeId, false) == null) { this.languageNameWarningMessage = - messages.get("jsf.language.validation.UnknownPluralForm"); + msgs.get("jsf.language.validation.UnknownPluralForm"); } // Check for similar already registered languages (warning) List similarLangs = localeDAO.findBySimilarLocaleId(localeId); if (similarLangs.size() > 0) { this.languageNameWarningMessage = - messages.get("jsf.language.validation.SimilarLocaleFound") + msgs.get("jsf.language.validation.SimilarLocaleFound") + similarLangs.get(0).getLocaleId().getId(); } diff --git a/zanata-war/src/main/java/org/zanata/action/NewProfileAction.java b/zanata-war/src/main/java/org/zanata/action/NewProfileAction.java index eb7647617b..f6d6ee5673 100644 --- a/zanata-war/src/main/java/org/zanata/action/NewProfileAction.java +++ b/zanata-war/src/main/java/org/zanata/action/NewProfileAction.java @@ -21,6 +21,7 @@ package org.zanata.action; import java.io.Serializable; + import lombok.extern.slf4j.Slf4j; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; @@ -30,8 +31,10 @@ import org.jboss.seam.annotations.Transactional; import org.jboss.seam.faces.FacesMessages; import org.zanata.ApplicationConfiguration; +import org.zanata.i18n.Messages; import org.zanata.security.AuthenticationType; import org.zanata.security.ZanataOpenId; +import org.zanata.service.EmailService; import org.zanata.service.RegisterService; /** @@ -47,6 +50,11 @@ public class NewProfileAction extends AbstractProfileAction implements Serializa @In private ZanataOpenId zanataOpenId; + @In + private EmailService emailServiceImpl; + @In + Messages msgs; + @In RegisterService registerServiceImpl; @@ -92,12 +100,10 @@ public void createUser() { .getAuthResult().getAuthenticatedId(), AuthenticationType.OPENID, this.name, this.email); } - setActivationKey(key); - renderer.render("/WEB-INF/facelets/email/email_activation.xhtml"); + String message = + emailServiceImpl.sendActivationEmail(this.name, this.email, key); identity.unAuthenticate(); - FacesMessages - .instance() - .add("You will soon receive an email with a link to activate your account."); + FacesMessages.instance().add(message); } public void cancel() { diff --git a/zanata-war/src/main/java/org/zanata/action/PasswordResetRequestAction.java b/zanata-war/src/main/java/org/zanata/action/PasswordResetRequestAction.java index f9e89cb794..f286a8f79a 100644 --- a/zanata-war/src/main/java/org/zanata/action/PasswordResetRequestAction.java +++ b/zanata-war/src/main/java/org/zanata/action/PasswordResetRequestAction.java @@ -5,9 +5,9 @@ import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.NotEmpty; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.End; @@ -15,13 +15,14 @@ import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.faces.FacesMessages; -import org.jboss.seam.faces.Renderer; import org.zanata.dao.AccountDAO; import org.zanata.model.HAccount; import org.zanata.model.HAccountResetPasswordKey; +import org.zanata.service.EmailService; import org.zanata.service.UserAccountService; @Name("passwordResetRequest") +@NoArgsConstructor @Scope(ScopeType.EVENT) @Slf4j public class PasswordResetRequestAction implements Serializable { @@ -29,13 +30,11 @@ public class PasswordResetRequestAction implements Serializable { @In private AccountDAO accountDAO; - + @In + private EmailService emailServiceImpl; @In private UserAccountService userAccountServiceImpl; - @In(create = true) - private Renderer renderer; - private String username; private String email; private String activationKey; @@ -61,7 +60,7 @@ public void setEmail(String email) { this.email = email; } - @Email + @org.hibernate.validator.constraints.Email @NotEmpty public String getEmail() { return email; @@ -77,13 +76,10 @@ public String requestReset() { FacesMessages.instance().add("No such account found"); return null; } else { - setActivationKey(key.getKeyHash()); - renderer.render("/WEB-INF/facelets/email/password_reset.xhtml"); - log.info("Sent password reset key to {} ({})", account - .getPerson().getName(), account.getUsername()); - FacesMessages - .instance() - .add("You will soon receive an email with a link to reset your password."); + String message = + emailServiceImpl.sendPasswordResetEmail(account.getPerson(), + key.getKeyHash()); + FacesMessages.instance().add(message); return "/home.xhtml"; } diff --git a/zanata-war/src/main/java/org/zanata/action/ProjectHome.java b/zanata-war/src/main/java/org/zanata/action/ProjectHome.java index 161f41e5a5..b45a434e8b 100644 --- a/zanata-war/src/main/java/org/zanata/action/ProjectHome.java +++ b/zanata-war/src/main/java/org/zanata/action/ProjectHome.java @@ -48,11 +48,11 @@ import org.jboss.seam.faces.FacesMessages; import org.jboss.seam.international.StatusMessage; import org.jboss.seam.security.management.JpaIdentityStore; -import org.zanata.annotation.CachedMethodResult; import org.zanata.common.EntityStatus; import org.zanata.common.LocaleId; import org.zanata.common.ProjectType; import org.zanata.dao.AccountRoleDAO; +import org.zanata.i18n.Messages; import org.zanata.model.HAccount; import org.zanata.model.HAccountRole; import org.zanata.model.HLocale; @@ -65,12 +65,10 @@ import org.zanata.service.SlugEntityService; import org.zanata.service.ValidationService; import org.zanata.ui.AbstractListFilter; -import org.zanata.ui.FilterUtil; import org.zanata.ui.InMemoryListFilter; import org.zanata.ui.autocomplete.LocaleAutocomplete; import org.zanata.ui.autocomplete.MaintainerAutocomplete; import org.zanata.util.ComparatorUtil; -import org.zanata.util.ZanataMessages; import org.zanata.webtrans.shared.model.ValidationAction; import org.zanata.webtrans.shared.model.ValidationId; import org.zanata.webtrans.shared.validation.ValidationFactory; @@ -107,7 +105,7 @@ public class ProjectHome extends SlugHome { private EntityManager entityManager; @In - private ZanataMessages zanataMessages; + private Messages msgs; @In private AccountRoleDAO accountRoleDAO; @@ -123,6 +121,9 @@ public class ProjectHome extends SlugHome { private Map availableValidations = Maps .newHashMap(); + @Getter(lazy = true) + private final List versions = fetchVersions(); + @Getter @Setter private String selectedProjectType; @@ -200,7 +201,7 @@ public void removeLanguage(LocaleId localeId) { update(); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.project.LanguageRemoved", + msgs.format("jsf.project.LanguageRemoved", locale.retrieveDisplayName())); } @@ -209,8 +210,7 @@ public void updateLanguagesFromGlobal() { getInstance().setOverrideLocales(false); update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages - .getMessage("jsf.project.LanguageUpdateFromGlobal")); + msgs.get("jsf.project.LanguageUpdateFromGlobal")); } @Restrict("#{s:hasPermission(projectHome.instance, 'update')}") @@ -250,10 +250,11 @@ public void updateCopyTrans(String action, String value) { update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.project.CopyTransOpts.updated")); + msgs.get("jsf.project.CopyTransOpts.updated")); } public void initialize() { + initInstance(); validateSuppliedId(); if (getInstance().getDefaultCopyTransOpts() != null) { copyTransOptionsModel.setInstance(getInstance() @@ -292,7 +293,6 @@ private void updateProjectType() { @Override @Transactional public String persist() { - conversationScopeMessages.clearMessages(); String retValue = ""; if (!validateSlug(getInstance().getSlug(), "slug")) { return null; @@ -338,15 +338,15 @@ public List getInstanceMaintainers() { public String removeMaintainer(HPerson person) { if (getInstanceMaintainers().size() <= 1) { conversationScopeMessages - .setMessage(FacesMessage.SEVERITY_INFO, zanataMessages - .getMessage("jsf.project.NeedAtLeastOneMaintainer")); + .setMessage(FacesMessage.SEVERITY_INFO, + msgs.get("jsf.project.NeedAtLeastOneMaintainer")); } else { getInstance().getMaintainers().remove(person); maintainerFilter.reset(); update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.project.MaintainerRemoved", + msgs.format("jsf.project.MaintainerRemoved", person.getName())); // force page to do url redirect to project page. See pages.xml @@ -373,7 +373,7 @@ public void updateRoles(String roleName, boolean isRestricted) { } update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.RolesUpdated")); + msgs.get("jsf.RolesUpdated")); } @Restrict("#{s:hasPermission(projectHome.instance, 'update')}") @@ -403,7 +403,7 @@ public void updateStatus(char initial) { update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.project.status.updated", + msgs.format("jsf.project.status.updated", EntityStatus.valueOf(initial))); } @@ -431,8 +431,7 @@ public List getAvailableRoles() { return allRoles; } - @CachedMethodResult - public List getVersions() { + private List fetchVersions() { List results = new ArrayList(); for (HProjectIteration iteration : getInstance().getProjectIterations()) { @@ -522,7 +521,7 @@ public void updateValidationOption(String name, String state) { update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.validation.updated", + msgs.format("jsf.validation.updated", validatationId.getDisplayName(), state)); } @@ -600,7 +599,7 @@ public void onSelectItemAction() { reset(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.project.MaintainerAdded", + msgs.format("jsf.project.MaintainerAdded", maintainer.getName())); } } @@ -633,7 +632,7 @@ public void onSelectItemAction() { update(conversationScopeMessages); reset(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.project.LanguageAdded", + msgs.format("jsf.project.LanguageAdded", locale.retrieveDisplayName())); } } diff --git a/zanata-war/src/main/java/org/zanata/action/ProjectHomeAction.java b/zanata-war/src/main/java/org/zanata/action/ProjectHomeAction.java index 60ed945c29..d920bd7f5d 100644 --- a/zanata-war/src/main/java/org/zanata/action/ProjectHomeAction.java +++ b/zanata-war/src/main/java/org/zanata/action/ProjectHomeAction.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import javax.annotation.Nullable; +import javax.faces.application.FacesMessage; import org.apache.commons.lang.StringUtils; import org.jboss.seam.ScopeType; @@ -37,14 +38,18 @@ import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.security.management.JpaIdentityStore; -import org.zanata.annotation.CachedMethodResult; +import org.zanata.async.tasks.CopyVersionTask; import org.zanata.common.EntityStatus; import org.zanata.dao.LocaleMemberDAO; import org.zanata.dao.ProjectDAO; +import org.zanata.dao.ProjectIterationDAO; +import org.zanata.i18n.Messages; import org.zanata.model.Activity; import org.zanata.model.HAccount; import org.zanata.model.HLocale; +import org.zanata.model.HProject; import org.zanata.model.HProjectIteration; +import org.zanata.seam.scope.ConversationScopeMessages; import org.zanata.security.ZanataIdentity; import org.zanata.service.ActivityService; import org.zanata.service.LocaleService; @@ -56,8 +61,6 @@ import org.zanata.util.ComparatorUtil; import org.zanata.util.DateUtil; import org.zanata.util.StatisticsUtil; -import org.zanata.util.UrlUtil; -import org.zanata.util.ZanataMessages; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; @@ -83,9 +86,6 @@ public class ProjectHomeAction extends AbstractSortAction implements @In private VersionStateCache versionStateCacheImpl; - @In - private UrlUtil urlUtil; - @In private ProjectDAO projectDAO; @@ -99,12 +99,21 @@ public class ProjectHomeAction extends AbstractSortAction implements private ZanataIdentity identity; @In - private ZanataMessages zanataMessages; + private CopyVersionManager copyVersionManager; + + @In + private Messages msgs; @Setter @Getter private String slug; + @In + private ProjectIterationDAO projectIterationDAO; + + @In + private ConversationScopeMessages conversationScopeMessages; + @Getter private SortingType VersionSortingList = new SortingType( Lists.newArrayList(SortingType.SortOption.ALPHABETICAL, @@ -134,18 +143,79 @@ protected boolean include(HProjectIteration elem, private List projectVersions; - private Map statisticMap; + private Map statisticMap = Maps.newHashMap(); private final VersionComparator versionComparator = new VersionComparator( getVersionSortingList()); + @Getter(lazy = true) + private final List projectLastActivity = + fetchProjectLastActivity(); + // for storing last activity date for the version private Map versionLatestActivityDate = Maps.newHashMap(); - @CachedMethodResult - public List getProjectLastActivity() { + public boolean isVersionCopying(String projectSlug, String versionSlug) { + return copyVersionManager + .isCopyVersionRunning(projectSlug, versionSlug); + } + + public String + getCopiedDocumentCount(String projectSlug, String versionSlug) { + CopyVersionTask.CopyVersionTaskHandle handler = + copyVersionManager.getCopyVersionProcessHandle(projectSlug, + versionSlug); + + if (handler == null) { + return "0"; + } else { + return String.valueOf(handler.getDocumentCopied()); + } + } + + public void cancelCopyVersion(String projectSlug, String versionSlug) { + copyVersionManager.cancelCopyVersion(projectSlug, versionSlug); + conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, + msgs.format("jsf.copyVersion.Cancelled", versionSlug)); + } + + public String getCopyVersionCompletePercent(String projectSlug, + String versionSlug) { + CopyVersionTask.CopyVersionTaskHandle handler = + copyVersionManager.getCopyVersionProcessHandle(projectSlug, + versionSlug); + + if (handler != null) { + double completedPercent = + (double) handler.getCurrentProgress() / (double) handler + .getMaxProgress() * 100; + if (Double.compare(completedPercent, 100) == 0) { + conversationScopeMessages.setMessage( + FacesMessage.SEVERITY_INFO, + msgs.format("jsf.copyVersion.Completed", versionSlug)); + } + return String.format("%1$,.2f", completedPercent); + } else { + return "0"; + } + } + + public String getCopyVersionTotalDocuments(String projectSlug, + String versionSlug) { + CopyVersionTask.CopyVersionTaskHandle handler = + copyVersionManager.getCopyVersionProcessHandle(projectSlug, + versionSlug); + + if (handler == null) { + return "0"; + } else { + return String.valueOf(handler.getTotalDoc()); + } + } + + private List fetchProjectLastActivity() { if (StringUtils.isEmpty(slug) || !identity.isLoggedIn()) { - return Lists.newArrayList(); + return Collections.EMPTY_LIST; } Collection versionIds = @@ -163,7 +233,6 @@ public List getProjectLastActivity() { Lists.newArrayList(versionIds), 0, 1); } - @CachedMethodResult public DisplayUnit getStatisticFigureForVersion( SortingType.SortOption sortOption, HProjectIteration version) { WordStatistic statistic = getStatisticForVersion(version.getSlug()); @@ -171,14 +240,6 @@ public DisplayUnit getStatisticFigureForVersion( return getDisplayUnit(sortOption, statistic, version.getLastChanged()); } - @CachedMethodResult - public WordStatistic getStatisticForVersion(String versionSlug) { - WordStatistic statistic = statisticMap.get(versionSlug); - statistic - .setRemainingHours(StatisticsUtil.getRemainingHours(statistic)); - return statistic; - } - /** * Sort version list */ @@ -262,32 +323,57 @@ private Date getVersionLastActivityDate(Long versionId) { return versionLatestActivityDate.get(versionId); } + public void clearVersionStats(String versionSlug) { + statisticMap.remove(versionSlug); + } + + public WordStatistic getStatisticForVersion(String versionSlug) { + WordStatistic statistic; + if (statisticMap.containsKey(versionSlug)) { + statistic = statisticMap.get(versionSlug); + } else { + HProjectIteration version = + projectIterationDAO.getBySlug(slug, versionSlug); + statistic = getAllLocaleStatisticForVersion(version); + statisticMap.put(versionSlug, statistic); + } + statistic + .setRemainingHours(StatisticsUtil.getRemainingHours(statistic)); + return statistic; + } + @Override protected void loadStatistics() { - statisticMap = Maps.newHashMap(); + statisticMap.clear(); for (HProjectIteration version : getProjectVersions()) { - WordStatistic versionStats = new WordStatistic(); - List locales = getSupportedLocale(version); - for (HLocale locale : locales) { - versionStats.add(versionStateCacheImpl.getVersionStatistics( - version.getId(), locale.getLocaleId())); - } - statisticMap.put(version.getSlug(), versionStats); + statisticMap.put(version.getSlug(), + getAllLocaleStatisticForVersion(version)); } } + private WordStatistic getAllLocaleStatisticForVersion( + HProjectIteration version) { + WordStatistic versionStats = new WordStatistic(); + List locales = getSupportedLocale(version); + for (HLocale locale : locales) { + versionStats.add(versionStateCacheImpl.getVersionStatistics( + version.getId(), locale.getLocaleId())); + } + return versionStats; + } + public List getSupportedLocale(HProjectIteration version) { if (version != null) { return localeServiceImpl.getSupportedLanguageByProjectIteration( slug, version.getSlug()); } - return Lists.newArrayList(); + return Collections.EMPTY_LIST; } public List getUserJoinedLocales(HProjectIteration version) { if (authenticatedAccount == null) { - return Lists.newArrayList(); + return Collections.EMPTY_LIST; } List userJoinedLocales = Lists.newArrayList(); @@ -359,10 +445,6 @@ public void resetPageData() { @Override protected String getMessage(String key, Object... args) { - return zanataMessages.getMessage(key, args); - } - - public String getCreateVersionUrl(String projectSlug) { - return urlUtil.createNewVersionUrl(projectSlug); + return msgs.format(key, args); } } diff --git a/zanata-war/src/main/java/org/zanata/action/ProjectPagedListDataModel.java b/zanata-war/src/main/java/org/zanata/action/ProjectPagedListDataModel.java index 09fde7bd65..b1c8975918 100644 --- a/zanata-war/src/main/java/org/zanata/action/ProjectPagedListDataModel.java +++ b/zanata-war/src/main/java/org/zanata/action/ProjectPagedListDataModel.java @@ -23,10 +23,9 @@ import java.io.Serializable; import java.util.List; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; import org.zanata.dao.ProjectDAO; import org.zanata.model.HProject; +import org.zanata.util.ServiceLocator; public class ProjectPagedListDataModel extends PagedListDataModel implements Serializable { @@ -46,8 +45,7 @@ public ProjectPagedListDataModel(boolean filterActive, @Override public DataPage fetchPage(int startRow, int pageSize) { ProjectDAO projectDAO = - (ProjectDAO) Component.getInstance(ProjectDAO.class, - ScopeType.STATELESS); + ServiceLocator.instance().getInstance(ProjectDAO.class); List proj = projectDAO.getOffsetListOrderByName(startRow, pageSize, filterActive, filterReadOnly, filterObsolete); diff --git a/zanata-war/src/main/java/org/zanata/action/ProjectSearch.java b/zanata-war/src/main/java/org/zanata/action/ProjectSearch.java index d8cc78556c..56abea8067 100644 --- a/zanata-war/src/main/java/org/zanata/action/ProjectSearch.java +++ b/zanata-war/src/main/java/org/zanata/action/ProjectSearch.java @@ -12,7 +12,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.lucene.queryParser.ParseException; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; @@ -24,6 +23,7 @@ import com.google.common.collect.Lists; import org.zanata.ui.AbstractAutocomplete; +import org.zanata.util.ServiceLocator; @Name("projectSearch") @Scope(ScopeType.CONVERSATION) @@ -66,8 +66,8 @@ public boolean isProjectNull() { private class ProjectAutocomplete extends AbstractAutocomplete { - private ProjectDAO projectDAO = (ProjectDAO) Component - .getInstance(ProjectDAO.class); + private ProjectDAO projectDAO = + ServiceLocator.instance().getInstance(ProjectDAO.class); /** * Return results on search @@ -81,7 +81,7 @@ public List suggest() { try { List searchResult = projectDAO.searchProjects( - getQuery(), + getQuery().trim(), INITIAL_RESULT_COUNT, 0, ZanataIdentity.instance().hasPermission( diff --git a/zanata-war/src/main/java/org/zanata/action/QueryProjectPagedListDataModel.java b/zanata-war/src/main/java/org/zanata/action/QueryProjectPagedListDataModel.java index a7fcc89292..5e9e1ecd8c 100644 --- a/zanata-war/src/main/java/org/zanata/action/QueryProjectPagedListDataModel.java +++ b/zanata-war/src/main/java/org/zanata/action/QueryProjectPagedListDataModel.java @@ -25,13 +25,12 @@ import java.util.List; import org.apache.lucene.queryParser.ParseException; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; import org.zanata.dao.ProjectDAO; import org.zanata.model.HProject; import lombok.Getter; import lombok.Setter; +import org.zanata.util.ServiceLocator; /** * @see org.zanata.action.EntityPagedListDataModel @@ -54,8 +53,7 @@ public QueryProjectPagedListDataModel(int pageSize) { @Override public DataPage fetchPage(int startRow, int pageSize) { ProjectDAO projectDAO = - (ProjectDAO) Component.getInstance(ProjectDAO.class, - ScopeType.STATELESS); + ServiceLocator.instance().getInstance(ProjectDAO.class); try { List proj = diff --git a/zanata-war/src/main/java/org/zanata/action/RegisterAction.java b/zanata-war/src/main/java/org/zanata/action/RegisterAction.java index 00b7be6abc..c4c7cf3724 100644 --- a/zanata-war/src/main/java/org/zanata/action/RegisterAction.java +++ b/zanata-war/src/main/java/org/zanata/action/RegisterAction.java @@ -167,9 +167,7 @@ public String register() { log.info("get register key:" + key); String message = - emailServiceImpl.sendActivationEmail( - EmailService.ACTIVATION_ACCOUNT_EMAIL_TEMPLATE, user, - email, key); + emailServiceImpl.sendActivationEmail(user, email, key); FacesMessages.instance().add(message); return "/home.xhtml"; diff --git a/zanata-war/src/main/java/org/zanata/action/SendEmailAction.java b/zanata-war/src/main/java/org/zanata/action/SendEmailAction.java index c09cc74ef7..dd419feae1 100644 --- a/zanata-war/src/main/java/org/zanata/action/SendEmailAction.java +++ b/zanata-war/src/main/java/org/zanata/action/SendEmailAction.java @@ -21,13 +21,16 @@ package org.zanata.action; import java.io.Serializable; -import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Locale; import javax.faces.application.FacesMessage; +import com.google.common.collect.Lists; +import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Email; import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; @@ -36,18 +39,27 @@ import org.jboss.seam.international.LocaleSelector; import org.jboss.seam.security.management.JpaIdentityStore; import org.zanata.common.LocaleId; +import org.zanata.email.EmailStrategy; import org.zanata.model.HAccount; import org.zanata.model.HLocale; -import org.zanata.model.HLocaleMember; import org.zanata.model.HPerson; +import org.zanata.model.HProjectIteration; import org.zanata.seam.scope.ConversationScopeMessages; import org.zanata.service.EmailService; import org.zanata.service.LocaleService; -import org.zanata.util.ZanataMessages; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.zanata.webtrans.shared.model.ProjectIterationId; + +import org.zanata.email.ContactAdminEmailStrategy; +import org.zanata.email.ContactLanguageCoordinatorEmailStrategy; + +import org.zanata.email.RequestRoleLanguageEmailStrategy; + +import org.zanata.email.RequestToJoinLanguageEmailStrategy; +import org.zanata.email.RequestToJoinVersionGroupEmailStrategy; /** * Sends an email to a specified role. @@ -57,7 +69,9 @@ * @author damason@redhat.com * */ +@AutoCreate @Name("sendEmail") +@NoArgsConstructor @Scope(ScopeType.PAGE) @Slf4j public class SendEmailAction implements Serializable { @@ -73,6 +87,12 @@ public class SendEmailAction implements Serializable { private static final String EMAIL_TYPE_REQUEST_TO_JOIN_GROUP = "request_to_join_group"; + @In + private LanguageJoinUpdateRoleAction languageJoinUpdateRoleAction; + + @In + private VersionGroupJoinAction versionGroupJoinAction; + @In private EmailService emailServiceImpl; @@ -121,9 +141,6 @@ public class SendEmailAction implements Serializable { private List groupMaintainers; - @In - private ZanataMessages zanataMessages; - public static final String SUCCESS = "success"; public static final String FAILED = "failure"; @@ -146,17 +163,6 @@ public void setLanguage(String language) { locale = localeServiceImpl.getByLocaleId(new LocaleId(language)); } - private List getCoordinators() { - List coordinators = new ArrayList(); - - for (HLocaleMember member : locale.getMembers()) { - if (member.isCoordinator()) { - coordinators.add(member.getPerson()); - } - } - return coordinators; - } - /** * Sends the email by rendering an appropriate email template with the * values in this bean. @@ -170,54 +176,86 @@ public String send() { try { if (emailType.equals(EMAIL_TYPE_CONTACT_ADMIN)) { - String msg = - emailServiceImpl - .sendToAdminEmails( - EmailService.ADMIN_EMAIL_TEMPLATE, - fromName, fromLoginName, replyEmail, - subject, htmlMessage); + EmailStrategy strategy = new ContactAdminEmailStrategy( + fromLoginName, fromName, replyEmail, + subject, htmlMessage); + + String msg = emailServiceImpl.sendToAdmins(strategy); + FacesMessages.instance().add(msg); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, msg); return SUCCESS; } else if (emailType.equals(EMAIL_TYPE_CONTACT_COORDINATOR)) { - String msg = - emailServiceImpl.sendToLanguageCoordinators( - EmailService.COORDINATOR_EMAIL_TEMPLATE, - getCoordinators(), fromName, fromLoginName, - replyEmail, subject, htmlMessage, language); + String localeNativeName = locale.retrieveNativeName(); + + EmailStrategy strategy = new ContactLanguageCoordinatorEmailStrategy( + fromLoginName, fromName, replyEmail, subject, + locale.getLocaleId().getId(), + localeNativeName, htmlMessage); + String msg = emailServiceImpl.sendToLanguageCoordinators( + locale, strategy); + FacesMessages.instance().add(msg); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, msg); return SUCCESS; } else if (emailType.equals(EMAIL_TYPE_REQUEST_JOIN)) { - String msg = - emailServiceImpl.sendToLanguageCoordinators( - EmailService.REQUEST_TO_JOIN_EMAIL_TEMPLATE, - getCoordinators(), fromName, fromLoginName, - replyEmail, subject, htmlMessage, language); + String localeNativeName = locale.retrieveNativeName(); + + EmailStrategy strategy = new RequestToJoinLanguageEmailStrategy( + fromLoginName, fromName, replyEmail, + locale.getLocaleId().getId(), + localeNativeName, htmlMessage, + languageJoinUpdateRoleAction.getRequestAsTranslator(), + languageJoinUpdateRoleAction.getRequestAsReviewer(), + languageJoinUpdateRoleAction.getRequestAsCoordinator()); + String msg = emailServiceImpl.sendToLanguageCoordinators( + locale, strategy); FacesMessages.instance().add(msg); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, msg); return SUCCESS; } else if (emailType.equals(EMAIL_TYPE_REQUEST_ROLE)) { - String msg = - emailServiceImpl.sendToLanguageCoordinators( - EmailService.REQUEST_ROLE_EMAIL_TEMPLATE, - getCoordinators(), fromName, fromLoginName, - replyEmail, subject, htmlMessage, language); + String localeNativeName = locale.retrieveNativeName(); + + EmailStrategy strategy = new RequestRoleLanguageEmailStrategy( + fromLoginName, fromName, replyEmail, + locale.getLocaleId().getId(), + localeNativeName, htmlMessage, + languageJoinUpdateRoleAction.requestingTranslator(), + languageJoinUpdateRoleAction.requestingReviewer(), + languageJoinUpdateRoleAction.requestingCoordinator()); + String msg = emailServiceImpl.sendToLanguageCoordinators( + locale, strategy); FacesMessages.instance().add(msg); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, msg); return SUCCESS; } else if (emailType.equals(EMAIL_TYPE_REQUEST_TO_JOIN_GROUP)) { + String groupSlug = versionGroupJoinAction.getSlug(); + String groupName = versionGroupJoinAction.getGroupName(); + Collection projectIterIds = Lists.newArrayList(); + + for (VersionGroupJoinAction.SelectableProject version : versionGroupJoinAction.getProjectVersions()) { + if (version.isSelected()) { + HProjectIteration projIter = + version.getProjectIteration(); + projectIterIds.add(new ProjectIterationId( + projIter.getProject().getSlug(), + projIter.getSlug(), + projIter.getProjectType())); + } + } + + EmailStrategy strategy = new RequestToJoinVersionGroupEmailStrategy( + fromLoginName, fromName, replyEmail, + groupName, groupSlug, + projectIterIds, htmlMessage); String msg = emailServiceImpl - .sendToVersionGroupMaintainer( - EmailService.REQUEST_TO_JOIN_GROUP_EMAIL_TEMPLATE, - groupMaintainers, fromName, - fromLoginName, replyEmail, subject, - htmlMessage); + .sendToVersionGroupMaintainers( + groupMaintainers, strategy); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, msg); return SUCCESS; diff --git a/zanata-war/src/main/java/org/zanata/action/ServerConfigurationBean.java b/zanata-war/src/main/java/org/zanata/action/ServerConfigurationBean.java index b36896cdd3..d6969223ee 100644 --- a/zanata-war/src/main/java/org/zanata/action/ServerConfigurationBean.java +++ b/zanata-war/src/main/java/org/zanata/action/ServerConfigurationBean.java @@ -21,14 +21,18 @@ package org.zanata.action; import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; import javax.validation.constraints.Pattern; -import lombok.AccessLevel; +import lombok.Data; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; import org.hibernate.validator.constraints.Email; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; @@ -38,93 +42,132 @@ import org.jboss.seam.annotations.Transactional; import org.jboss.seam.annotations.security.Restrict; import org.jboss.seam.faces.FacesMessages; -import org.jboss.seam.international.StatusMessage; import org.zanata.ApplicationConfiguration; import org.zanata.action.validator.EmailList; import org.zanata.dao.ApplicationConfigurationDAO; import org.zanata.model.HApplicationConfiguration; import org.zanata.model.validator.Url; import org.zanata.rest.service.ServerConfigurationService; -import com.google.common.base.Strings; + +import static org.zanata.model.HApplicationConfiguration.*; @Name("serverConfigurationBean") @Scope(ScopeType.PAGE) @Restrict("#{s:hasRole('admin')}") -@Getter -@Setter @Slf4j public class ServerConfigurationBean implements Serializable { private static final long serialVersionUID = 1L; @In - @Setter(AccessLevel.NONE) - @Getter(AccessLevel.NONE) private ApplicationConfigurationDAO applicationConfigurationDAO; @In - @Setter(AccessLevel.NONE) - @Getter(AccessLevel.NONE) private ApplicationConfiguration applicationConfiguration; @Url(canEndInSlash = true) + @Getter + @Setter private String registerUrl; @Url(canEndInSlash = false) + @Getter + @Setter private String serverUrl; + @Getter + @Setter private String emailDomain; @EmailList + @Getter + @Setter private String adminEmail; @Email + @Getter + @Setter private String fromEmailAddr; + private PropertyWithKey fromEmailAddrProperty = new PropertyWithKey("fromEmailAddr", KEY_EMAIL_FROM_ADDRESS); private String homeContent; + private PropertyWithKey homeContentProperty = new PropertyWithKey("homeContent", KEY_HOME_CONTENT); private String helpContent; + private PropertyWithKey helpContentProperty = new PropertyWithKey("helpContent", KEY_HELP_CONTENT); + @Getter + @Setter private boolean enableLogEmail; + private PropertyWithKey enableLogEmailProperty = new PropertyWithKey("enableLogEmail", KEY_EMAIL_LOG_EVENTS); + @Getter + @Setter private String logDestinationEmails; + @Getter + @Setter private String logEmailLevel; @Url(canEndInSlash = true) + @Getter + @Setter private String piwikUrl; + @Getter + @Setter private String piwikIdSite; @Url(canEndInSlash = true) + @Getter + @Setter private String termsOfUseUrl; @Pattern(regexp = "\\d{0,5}") + @Getter + @Setter private String maxConcurrentRequestsPerApiKey; @Pattern(regexp = "\\d{0,5}") + @Getter + @Setter private String maxActiveRequestsPerApiKey; + @Pattern(regexp = "\\d{0,5}") + @Getter + @Setter + private String maxFilesPerUpload; + + private List> commonStringProperties = Arrays.asList( + new PropertyWithKey("registerUrl", KEY_REGISTER), + new PropertyWithKey("serverUrl", KEY_HOST), + new PropertyWithKey("emailDomain", KEY_DOMAIN), + new PropertyWithKey("adminEmail", KEY_ADMIN_EMAIL), + new PropertyWithKey("logDestinationEmails", KEY_LOG_DESTINATION_EMAIL), + new PropertyWithKey("logEmailLevel", KEY_EMAIL_LOG_LEVEL), + new PropertyWithKey("piwikUrl", KEY_PIWIK_URL), + new PropertyWithKey("piwikIdSite", KEY_PIWIK_IDSITE), + new PropertyWithKey("termsOfUseUrl", KEY_TERMS_CONDITIONS_URL), + new PropertyWithKey("maxConcurrentRequestsPerApiKey", KEY_MAX_CONCURRENT_REQ_PER_API_KEY), + new PropertyWithKey("maxActiveRequestsPerApiKey", KEY_MAX_ACTIVE_REQ_PER_API_KEY), + new PropertyWithKey("maxFilesPerUpload", KEY_MAX_FILES_PER_UPLOAD) + ); + public String getHomeContent() { HApplicationConfiguration var = applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_HOME_CONTENT); + .findByKey(homeContentProperty.getKey()); return var != null ? var.getValue() : ""; } public String getHelpContent() { HApplicationConfiguration var = applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_HELP_CONTENT); + .findByKey(helpContentProperty.getKey()); return var != null ? var.getValue() : ""; } public String updateHomeContent() { - HApplicationConfiguration var = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_HOME_CONTENT); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_HOME_CONTENT, - var, homeContent, applicationConfigurationDAO); + persistPropertyToDatabase(homeContentProperty); applicationConfigurationDAO.flush(); FacesMessages.instance().add("Home content was successfully updated."); @@ -132,12 +175,7 @@ public String updateHomeContent() { } public String updateHelpContent() { - HApplicationConfiguration var = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_HELP_CONTENT); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_HELP_CONTENT, - var, helpContent, applicationConfigurationDAO); + persistPropertyToDatabase(helpContentProperty); applicationConfigurationDAO.flush(); FacesMessages.instance().add( @@ -145,125 +183,51 @@ public String updateHelpContent() { return "/help/view.xhtml"; } - // TODO tech debt: all below code should really be cleaned up @Create public void onCreate() { - HApplicationConfiguration registerUrlValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_REGISTER); - if (registerUrlValue != null) { - this.registerUrl = registerUrlValue.getValue(); - } - HApplicationConfiguration serverUrlValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_HOST); - if (serverUrlValue != null) { - this.serverUrl = serverUrlValue.getValue(); - } - HApplicationConfiguration emailDomainValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_DOMAIN); - if (emailDomainValue != null) { - this.emailDomain = emailDomainValue.getValue(); - } - HApplicationConfiguration adminEmailValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_ADMIN_EMAIL); - if (adminEmailValue != null) { - this.adminEmail = adminEmailValue.getValue(); - } - + setPropertiesFromConfigIfNotNull(commonStringProperties); + setBooleanPropertyFromConfigIfNotNull(enableLogEmailProperty); this.fromEmailAddr = applicationConfiguration.getFromEmailAddr(); + } - HApplicationConfiguration emailLogEventsValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_EMAIL_LOG_EVENTS); - if (emailLogEventsValue != null) { - this.enableLogEmail = - Boolean.parseBoolean(emailLogEventsValue.getValue()); - } - HApplicationConfiguration logDestinationValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_LOG_DESTINATION_EMAIL); - if (logDestinationValue != null) { - this.logDestinationEmails = logDestinationValue.getValue(); - } - HApplicationConfiguration logEmailLevelValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_EMAIL_LOG_LEVEL); - if (logEmailLevelValue != null) { - this.logEmailLevel = logEmailLevelValue.getValue(); - } - HApplicationConfiguration piwikUrlValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_PIWIK_URL); - if (piwikUrlValue != null) { - this.piwikUrl = piwikUrlValue.getValue(); - } - HApplicationConfiguration piwikIdSiteValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_PIWIK_IDSITE); - if (piwikIdSiteValue != null) { - this.piwikIdSite = piwikIdSiteValue.getValue(); + private void setPropertiesFromConfigIfNotNull(List> properties) { + for (PropertyWithKey property : properties) { + setPropertyFromConfigIfNotNull(property); } + } - HApplicationConfiguration termsOfUseUrlValue = + private void setPropertyFromConfigIfNotNull(PropertyWithKey property) { + HApplicationConfiguration valueHolder = applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_TERMS_CONDITIONS_URL); - if (termsOfUseUrlValue != null) { - this.termsOfUseUrl = termsOfUseUrlValue.getValue(); - } - - HApplicationConfiguration maxConcurrent = applicationConfigurationDAO.findByKey( - HApplicationConfiguration.KEY_MAX_CONCURRENT_REQ_PER_API_KEY); - if (maxConcurrent != null) { - this.maxConcurrentRequestsPerApiKey = maxConcurrent.getValue(); + .findByKey(property.getKey()); + if (valueHolder != null) { + try { + property.set(valueHolder.getValue()); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } } + } - HApplicationConfiguration maxActive = applicationConfigurationDAO.findByKey( - HApplicationConfiguration.KEY_MAX_ACTIVE_REQ_PER_API_KEY); - if (maxActive != null) { - this.maxActiveRequestsPerApiKey = maxActive.getValue(); + private void setBooleanPropertyFromConfigIfNotNull(PropertyWithKey property) { + HApplicationConfiguration valueHolder = applicationConfigurationDAO.findByKey(property.getKey()); + if (valueHolder != null) { + try { + property.set(Boolean.parseBoolean(valueHolder.getValue())); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } } } @Transactional public String update() { - HApplicationConfiguration registerUrlValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_REGISTER); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_REGISTER, - registerUrlValue, registerUrl, applicationConfigurationDAO); - - HApplicationConfiguration serverUrlValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_HOST); - ServerConfigurationService - .persistApplicationConfig(HApplicationConfiguration.KEY_HOST, - serverUrlValue, serverUrl, applicationConfigurationDAO); - - HApplicationConfiguration emailDomainValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_DOMAIN); - ServerConfigurationService - .persistApplicationConfig(HApplicationConfiguration.KEY_DOMAIN, - emailDomainValue, emailDomain, - applicationConfigurationDAO); - - HApplicationConfiguration adminEmailValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_ADMIN_EMAIL); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_ADMIN_EMAIL, - adminEmailValue, adminEmail, applicationConfigurationDAO); - - HApplicationConfiguration fromEmailAddrValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_EMAIL_FROM_ADDRESS); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_EMAIL_FROM_ADDRESS, - fromEmailAddrValue, fromEmailAddr, applicationConfigurationDAO); + persistPropertiesToDatabase(commonStringProperties); + persistPropertyToDatabase(fromEmailAddrProperty); HApplicationConfiguration emailLogEventsValue = applicationConfigurationDAO @@ -278,60 +242,6 @@ public String update() { } applicationConfigurationDAO.makePersistent(emailLogEventsValue); - HApplicationConfiguration logDestEmailValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_LOG_DESTINATION_EMAIL); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_LOG_DESTINATION_EMAIL, - logDestEmailValue, logDestinationEmails, - applicationConfigurationDAO); - - HApplicationConfiguration logEmailLevelValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_EMAIL_LOG_LEVEL); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_EMAIL_LOG_LEVEL, - logEmailLevelValue, logEmailLevel, applicationConfigurationDAO); - - HApplicationConfiguration piwikUrlValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_PIWIK_URL); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_PIWIK_URL, - piwikUrlValue, piwikUrl, applicationConfigurationDAO); - - HApplicationConfiguration piwikIdSiteValue = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_PIWIK_IDSITE); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_PIWIK_IDSITE, - piwikIdSiteValue, piwikIdSite, applicationConfigurationDAO); - - HApplicationConfiguration termsOfUseUrlValue = - applicationConfigurationDAO - .findByKey( - HApplicationConfiguration.KEY_TERMS_CONDITIONS_URL); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_TERMS_CONDITIONS_URL, - termsOfUseUrlValue, termsOfUseUrl, applicationConfigurationDAO); - - HApplicationConfiguration maxConcurrent = - applicationConfigurationDAO - .findByKey( - HApplicationConfiguration.KEY_MAX_CONCURRENT_REQ_PER_API_KEY); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_MAX_CONCURRENT_REQ_PER_API_KEY, - maxConcurrent, maxConcurrentRequestsPerApiKey, - applicationConfigurationDAO); - - HApplicationConfiguration maxActive = - applicationConfigurationDAO - .findByKey(HApplicationConfiguration.KEY_MAX_ACTIVE_REQ_PER_API_KEY); - ServerConfigurationService.persistApplicationConfig( - HApplicationConfiguration.KEY_MAX_ACTIVE_REQ_PER_API_KEY, - maxActive, maxActiveRequestsPerApiKey, - applicationConfigurationDAO); - applicationConfigurationDAO.flush(); FacesMessages facesMessages = FacesMessages.instance(); facesMessages.clearGlobalMessages(); @@ -339,7 +249,47 @@ public String update() { return "success"; } + private void persistPropertiesToDatabase(List> properties) { + for (PropertyWithKey property : properties) { + persistPropertyToDatabase(property); + } + } + + private void persistPropertyToDatabase(PropertyWithKey property) { + HApplicationConfiguration registerUrlValue = + applicationConfigurationDAO + .findByKey(property.getKey()); + try { + ServerConfigurationService.persistApplicationConfig( + property.getKey(), + registerUrlValue, property.get(), applicationConfigurationDAO); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + public String cancel() { return "cancel"; } + + /** + * Associates a field of type T with a HApplicationConfiguration key, + * allowing abstraction around setting fields only if keys are bound. + */ + @Data + private class PropertyWithKey { + private final String propertyName; + private final String key; + + public void set(T value) throws InvocationTargetException, IllegalAccessException { + BeanUtils.setProperty(ServerConfigurationBean.this, propertyName, value); + } + public T get() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + return (T) BeanUtils.getProperty(ServerConfigurationBean.this, propertyName); + } + } } diff --git a/zanata-war/src/main/java/org/zanata/action/SortingType.java b/zanata-war/src/main/java/org/zanata/action/SortingType.java index 478d4efc9c..8d9c3f5797 100644 --- a/zanata-war/src/main/java/org/zanata/action/SortingType.java +++ b/zanata-war/src/main/java/org/zanata/action/SortingType.java @@ -3,11 +3,11 @@ import java.io.Serializable; import java.util.List; +import com.google.common.collect.Lists; + import lombok.Getter; import lombok.Setter; -import com.google.common.collect.Lists; - /** * @author Alex Eng aeng@redhat.com */ @@ -36,7 +36,7 @@ public enum SortOption { ALPHABETICAL("Alphabetical", true), LAST_ACTIVITY("Last activity", false), LAST_SOURCE_UPDATE("Last source updated", false), LAST_TRANSLATED("Last translated", false), LAST_UPDATED_BY_YOU( - "Last updated by you", false); + "Last updated by you", false), Entry("Entry", false); @Getter String display; diff --git a/zanata-war/src/main/java/org/zanata/action/TranslationMemoryAction.java b/zanata-war/src/main/java/org/zanata/action/TranslationMemoryAction.java index bd9c19f11f..dff1a0c11c 100644 --- a/zanata-war/src/main/java/org/zanata/action/TranslationMemoryAction.java +++ b/zanata-war/src/main/java/org/zanata/action/TranslationMemoryAction.java @@ -32,7 +32,6 @@ import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; @@ -49,6 +48,7 @@ import org.zanata.rest.service.TranslationMemoryResourceService; import org.zanata.service.AsyncTaskManagerService; import org.zanata.service.SlugEntityService; +import org.zanata.util.ServiceLocator; /** * Controller class for the Translation Memory UI. @@ -113,8 +113,9 @@ public void clearTransMemory(final String transMemorySlug) { @Override public Void call() throws Exception { TranslationMemoryResourceService tmResource = - (TranslationMemoryResourceService) Component - .getInstance("translationMemoryResource"); + ServiceLocator.instance().getInstance( + "translationMemoryResource", + TranslationMemoryResourceService.class); String msg = tmResource.deleteTranslationUnitsUnguarded( transMemorySlug).toString(); diff --git a/zanata-war/src/main/java/org/zanata/action/UserAction.java b/zanata-war/src/main/java/org/zanata/action/UserAction.java index 7b677afff1..0bb1858bac 100644 --- a/zanata-war/src/main/java/org/zanata/action/UserAction.java +++ b/zanata-war/src/main/java/org/zanata/action/UserAction.java @@ -21,7 +21,6 @@ package org.zanata.action; import java.util.List; -import java.util.Map; import javax.faces.model.DataModel; import javax.persistence.EntityManager; import javax.persistence.NoResultException; @@ -36,11 +35,13 @@ import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.faces.FacesMessages; -import org.jboss.seam.faces.Renderer; import org.jboss.seam.international.StatusMessage; import org.jboss.seam.security.management.IdentityManager; +import org.zanata.ApplicationConfiguration; import org.zanata.dao.AccountDAO; import org.zanata.dao.PersonDAO; +import org.zanata.i18n.Messages; +import org.zanata.service.EmailService; import org.zanata.service.UserAccountService; import lombok.Getter; @@ -70,7 +71,10 @@ public class UserAction extends private EntityManager entityManager; @In - private Map messages; + private ApplicationConfiguration applicationConfiguration; + + @In + private Messages msgs; @In private PersonDAO personDAO; @@ -78,8 +82,8 @@ public class UserAction extends @In private UserAccountService userAccountServiceImpl; - @In(create = true) - private Renderer renderer; + @In + private EmailService emailServiceImpl; private boolean newUserFlag; @@ -98,7 +102,8 @@ public void deleteUser(String userName) { FacesMessages .instance() .add(StatusMessage.Severity.ERROR, - messages.get("jsf.UserManager.delete.constraintViolation.error")); + msgs.get( + "jsf.UserManager.delete.constraintViolation.error")); } } } @@ -137,16 +142,18 @@ public void editUser(String username) { @Override public String save() { boolean usernameChanged = false; + String newUsername = getUsername(); // Allow user name changes when editing - if (!newUserFlag && !originalUsername.equals(getUsername())) { - if (isNewUsernameValid(getUsername())) { + if (!newUserFlag && !originalUsername.equals(newUsername)) { + if (isNewUsernameValid(newUsername)) { userAccountServiceImpl.editUsername(originalUsername, - getUsername()); + newUsername); usernameChanged = true; } else { FacesMessages.instance().addToControl("username", - messages.get("jsf.UsernameNotAvailable")); + msgs.format("jsf.UsernameNotAvailable", + getUsername())); setUsername(originalUsername); // reset the username field return "failure"; } @@ -155,7 +162,10 @@ public String save() { String saveResult = super.save(); if (usernameChanged) { - renderer.render("/WEB-INF/facelets/email/username_changed.xhtml"); + String email = getEmail(newUsername); + String message = emailServiceImpl.sendUsernameChangedEmail( + email, newUsername); + FacesMessages.instance().add(message); } return saveResult; } @@ -195,4 +205,5 @@ public DataPage fetchPage(int startRow, int pageSize) { return new DataPage(listSize, startRow, userList); } } + } diff --git a/zanata-war/src/main/java/org/zanata/action/UserSettingsAction.java b/zanata-war/src/main/java/org/zanata/action/UserSettingsAction.java index 46bea811cb..0a5f809676 100644 --- a/zanata-war/src/main/java/org/zanata/action/UserSettingsAction.java +++ b/zanata-war/src/main/java/org/zanata/action/UserSettingsAction.java @@ -25,21 +25,22 @@ import java.io.Serializable; import java.util.Collections; -import java.util.Comparator; import java.util.List; import javax.faces.context.ExternalContext; +import javax.mail.internet.InternetAddress; import javax.persistence.EntityManager; import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.Size; +import com.googlecode.totallylazy.collections.PersistentMap; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.NotEmpty; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.In; @@ -47,15 +48,15 @@ import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.Transactional; import org.jboss.seam.core.Conversation; -import org.jboss.seam.core.Events; import org.jboss.seam.faces.FacesMessages; -import org.jboss.seam.faces.Renderer; import org.jboss.seam.security.RunAsOperation; import org.jboss.seam.security.management.IdentityManager; import org.jboss.seam.security.management.JpaIdentityStore; import org.zanata.dao.AccountDAO; import org.zanata.dao.CredentialsDAO; import org.zanata.dao.PersonDAO; +import org.zanata.email.EmailStrategy; +import org.zanata.i18n.Messages; import org.zanata.model.HAccount; import org.zanata.model.HLocale; import org.zanata.model.HPerson; @@ -68,12 +69,13 @@ import org.zanata.security.openid.OpenIdAuthenticationResult; import org.zanata.security.openid.OpenIdProviderType; import org.zanata.security.openid.YahooOpenIdProvider; +import org.zanata.service.EmailService; import org.zanata.service.LanguageTeamService; import org.zanata.service.impl.EmailChangeService; import com.google.common.collect.Lists; import org.zanata.util.ComparatorUtil; -import org.zanata.util.ZanataMessages; +import org.zanata.util.ServiceLocator; /** * This is an action class that should eventually replace the @@ -89,15 +91,11 @@ @Slf4j public class UserSettingsAction { - @In(create = true) - protected Renderer renderer; - + @In + private EmailService emailServiceImpl; @In private EmailChangeService emailChangeService; - @In(create = true) - private ProfileAction profileAction; - @In private PersonDAO personDAO; @@ -114,7 +112,7 @@ public class UserSettingsAction { private LanguageTeamService languageTeamServiceImpl; @In - private ZanataMessages zanataMessages; + private Messages msgs; @In(value = JpaIdentityStore.AUTHENTICATED_USER) HAccount authenticatedAccount; @@ -169,14 +167,10 @@ public void updateEmail() { emailChangeService.generateActivationKey(person, emailAddress); // TODO create a separate field for newEmail, perhaps in this class - // TODO should template and messages.properties use userSettingsAction, not profileAction? - profileAction.setEmail(emailAddress); - profileAction.setActivationKey(activationKey); - renderer.render("/WEB-INF/facelets/email/email_validation.xhtml"); - - FacesMessages - .instance() - .add("You will soon receive an email with a link to activate your email account change."); + String message = + emailServiceImpl.sendEmailValidationEmail(this.accountName, + this.emailAddress, activationKey); + FacesMessages.instance().add(message); } } @@ -335,8 +329,7 @@ public void updateProfile() { authenticatedAccount.getPerson().setName( accountName ); personDAO.makePersistent(person); FacesMessages.instance().add( - zanataMessages.getMessage( - "jsf.dashboard.settings.profileUpdated.message")); + msgs.get("jsf.dashboard.settings.profileUpdated.message")); } // TODO Cache this @@ -353,8 +346,7 @@ public void leaveLanguageTeam(String localeId) { languageTeamServiceImpl.leaveLanguageTeam(localeId, authenticatedAccount.getPerson().getId()); FacesMessages.instance().add( - zanataMessages.getMessage( - "jsf.dashboard.settings.leaveLangTeam.message", + msgs.format("jsf.dashboard.settings.leaveLangTeam.message", localeId)); } @@ -378,10 +370,10 @@ public void afterOpenIdAuth(OpenIdAuthenticationResult result) { this.newCredentials.setEmail(result.getEmail()); // NB: Seam component injection won't work on callbacks EntityManager em = - (EntityManager) Component.getInstance("entityManager"); + ServiceLocator.instance().getEntityManager(); CredentialsDAO credentialsDAO = - (CredentialsDAO) Component - .getInstance(CredentialsDAO.class); + ServiceLocator.instance().getInstance( + CredentialsDAO.class); Conversation.instance().begin(true, false); // (To retain // messages) @@ -410,4 +402,5 @@ public String getRedirectToUrl() { // conversation } } + } diff --git a/zanata-war/src/main/java/org/zanata/action/VersionGroupHome.java b/zanata-war/src/main/java/org/zanata/action/VersionGroupHome.java index 5c64929740..0f40d3fcb5 100644 --- a/zanata-war/src/main/java/org/zanata/action/VersionGroupHome.java +++ b/zanata-war/src/main/java/org/zanata/action/VersionGroupHome.java @@ -32,7 +32,6 @@ import org.hibernate.Session; import org.hibernate.criterion.NaturalIdentifier; import org.hibernate.criterion.Restrictions; -import org.jboss.seam.Component; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.security.Restrict; @@ -40,6 +39,7 @@ import org.jboss.seam.security.management.JpaIdentityStore; import org.zanata.common.EntityStatus; import org.zanata.dao.ProjectIterationDAO; +import org.zanata.i18n.Messages; import org.zanata.model.HAccount; import org.zanata.model.HIterationGroup; import org.zanata.model.HLocale; @@ -55,7 +55,7 @@ import org.zanata.ui.autocomplete.LocaleAutocomplete; import org.zanata.ui.autocomplete.MaintainerAutocomplete; import org.zanata.util.ComparatorUtil; -import org.zanata.util.ZanataMessages; +import org.zanata.util.ServiceLocator; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; @@ -82,7 +82,7 @@ public class VersionGroupHome extends SlugHome { private SlugEntityService slugEntityServiceImpl; @In - private ZanataMessages zanataMessages; + private Messages msgs; @In private ConversationScopeMessages conversationScopeMessages; @@ -132,10 +132,14 @@ public boolean isSlugAvailable(String slug) { HIterationGroup.class); } + @Override + protected void updatedMessage() { + // Disable the default message from Seam + } + @Override @Restrict("#{s:hasPermission(versionGroupHome.instance, 'update')}") public String persist() { - conversationScopeMessages.clearMessages(); if (!validateSlug(getInstance().getSlug(), "slug")) return null; @@ -148,7 +152,6 @@ public String persist() { @Override @Restrict("#{s:hasPermission(versionGroupHome.instance, 'update')}") public String update() { - conversationScopeMessages.clearMessages(); return super.update(); } @@ -176,7 +179,7 @@ public void removeLanguage(HLocale locale) { update(); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.LanguageRemoveFromGroup", + msgs.format("jsf.LanguageRemoveFromGroup", locale.retrieveDisplayName())); } @@ -186,22 +189,21 @@ public void removeVersion(HProjectIteration version) { update(); conversationScopeMessages.setMessage( FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.VersionRemoveFromGroup", - version.getSlug(), version.getProject().getSlug())); + msgs.format("jsf.VersionRemoveFromGroup", version.getSlug(), + version.getProject().getSlug())); } @Restrict("#{s:hasPermission(versionGroupHome.instance, 'update')}") public void removeMaintainer(HPerson maintainer) { if (getInstance().getMaintainers().size() <= 1) { conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages - .getMessage("jsf.group.NeedAtLeastOneMaintainer")); + msgs.get("jsf.group.NeedAtLeastOneMaintainer")); } else { getInstance().removeMaintainer(maintainer); maintainerFilter.reset(); update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.MaintainerRemoveFromGroup", + msgs.format("jsf.MaintainerRemoveFromGroup", maintainer.getName())); } } @@ -281,20 +283,18 @@ public void onSelectItemAction() { update(conversationScopeMessages); reset(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.MaintainerAddedToGroup", + msgs.format("jsf.MaintainerAddedToGroup", maintainer.getName())); } } private class VersionAutocomplete extends AbstractAutocomplete { - private ProjectIterationDAO projectIterationDAO = - (ProjectIterationDAO) Component - .getInstance(ProjectIterationDAO.class); + private ProjectIterationDAO projectIterationDAO = ServiceLocator + .instance().getInstance(ProjectIterationDAO.class); - private VersionGroupService versionGroupServiceImpl = - (VersionGroupService) Component - .getInstance(VersionGroupServiceImpl.class); + private VersionGroupService versionGroupServiceImpl = ServiceLocator + .instance().getInstance(VersionGroupServiceImpl.class); @Override public List suggest() { @@ -329,8 +329,8 @@ public void onSelectItemAction() { reset(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.VersionAddedToGroup", - version.getSlug(), version.getProject().getSlug())); + msgs.format("jsf.VersionAddedToGroup", version.getSlug(), + version.getProject().getSlug())); } } @@ -377,7 +377,7 @@ public void onSelectItemAction() { update(conversationScopeMessages); reset(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.LanguageAddedToGroup", + msgs.format("jsf.LanguageAddedToGroup", locale.retrieveDisplayName())); } } diff --git a/zanata-war/src/main/java/org/zanata/action/VersionGroupHomeAction.java b/zanata-war/src/main/java/org/zanata/action/VersionGroupHomeAction.java index 39922d72ac..1b31db7c5d 100644 --- a/zanata-war/src/main/java/org/zanata/action/VersionGroupHomeAction.java +++ b/zanata-war/src/main/java/org/zanata/action/VersionGroupHomeAction.java @@ -33,11 +33,11 @@ import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.security.management.JpaIdentityStore; -import org.zanata.annotation.CachedMethodResult; import org.zanata.common.LocaleId; import org.zanata.dao.LocaleDAO; import org.zanata.dao.ProjectIterationDAO; import org.zanata.dao.VersionGroupDAO; +import org.zanata.i18n.Messages; import org.zanata.model.HAccount; import org.zanata.model.HLocale; import org.zanata.model.HPerson; @@ -51,7 +51,6 @@ import org.zanata.ui.model.statistic.WordStatistic; import org.zanata.util.ComparatorUtil; import org.zanata.util.StatisticsUtil; -import org.zanata.util.ZanataMessages; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -72,7 +71,7 @@ public class VersionGroupHomeAction extends AbstractSortAction implements private VersionGroupService versionGroupServiceImpl; @In - private ZanataMessages zanataMessages; + private Messages msgs; @In(required = false, value = JpaIdentityStore.AUTHENTICATED_USER) private HAccount authenticatedAccount; @@ -110,6 +109,10 @@ public class VersionGroupHomeAction extends AbstractSortAction implements private Map> missingLocaleVersionMap; + private final Map localeStats = Maps.newHashMap(); + + private final Map projectStats = Maps.newHashMap(); + @Getter private SortingType projectSortingList = new SortingType( Lists.newArrayList(SortingType.SortOption.ALPHABETICAL, @@ -364,7 +367,6 @@ public List getActiveLocales() { return activeLocales; } - @CachedMethodResult public DisplayUnit getStatisticFigureForProjectWithLocale( SortingType.SortOption sortOption, LocaleId localeId, Long projectIterationId) { @@ -374,56 +376,56 @@ public DisplayUnit getStatisticFigureForProjectWithLocale( return getDisplayUnit(sortOption, statistic, null); } - @CachedMethodResult public DisplayUnit getStatisticFigureForLocale( SortingType.SortOption sortOption, LocaleId localeId) { WordStatistic statistic = getStatisticsForLocale(localeId); return getDisplayUnit(sortOption, statistic, null); } - @CachedMethodResult public DisplayUnit getStatisticFigureForProject( SortingType.SortOption sortOption, Long projectIterationId) { WordStatistic statistic = getStatisticForProject(projectIterationId); return getDisplayUnit(sortOption, statistic, null); } - @CachedMethodResult public WordStatistic getStatisticsForLocale(LocaleId localeId) { - WordStatistic statistic = new WordStatistic(); - for (Map.Entry entry : statisticMap - .entrySet()) { - if (entry.getKey().getLocaleId().equals(localeId)) { - statistic.add(entry.getValue()); + if( !localeStats.containsKey(localeId) ) { + WordStatistic statistic = new WordStatistic(); + for (Map.Entry entry : statisticMap + .entrySet()) { + if (entry.getKey().getLocaleId().equals(localeId)) { + statistic.add(entry.getValue()); + } } + statistic + .setRemainingHours(StatisticsUtil.getRemainingHours(statistic)); + localeStats.put(localeId, statistic); } - statistic - .setRemainingHours(StatisticsUtil.getRemainingHours(statistic)); - return statistic; + return localeStats.get(localeId); } - @CachedMethodResult public WordStatistic getStatisticForProject(Long projectIterationId) { - WordStatistic statistic = new WordStatistic(); - for (Map.Entry entry : statisticMap - .entrySet()) { - if (entry.getKey().getProjectIterationId() - .equals(projectIterationId)) { - statistic.add(entry.getValue()); + if( !projectStats.containsKey(projectIterationId) ) { + WordStatistic statistic = new WordStatistic(); + for (Map.Entry entry : statisticMap + .entrySet()) { + if (entry.getKey().getProjectIterationId() + .equals(projectIterationId)) { + statistic.add(entry.getValue()); + } } + statistic + .setRemainingHours(StatisticsUtil.getRemainingHours(statistic)); + projectStats.put(projectIterationId, statistic); } - statistic - .setRemainingHours(StatisticsUtil.getRemainingHours(statistic)); - return statistic; + return projectStats.get(projectIterationId); } - @CachedMethodResult public WordStatistic getSelectedLocaleStatistic(Long projectIterationId) { return statisticMap.get(new VersionLocaleKey(projectIterationId, selectedLocale.getLocaleId())); } - @CachedMethodResult public WordStatistic getSelectedVersionStatistic(LocaleId localeId) { return statisticMap.get(new VersionLocaleKey(selectedVersion.getId(), localeId)); @@ -464,10 +466,9 @@ public List getMissingLocale(HProjectIteration version) { public String getMissingLocaleTitle(HProjectIteration version) { int size = getMissingLocale(version).size(); if (size > 1) { - return zanataMessages.getMessage("jsf.LanguagesMissingProject", - size); + return msgs.format("jsf.LanguagesMissingProject", size); } - return zanataMessages.getMessage("jsf.LanguageMissingProject", size); + return msgs.format("jsf.LanguageMissingProject", size); } /** @@ -479,16 +480,15 @@ public List getMissingVersion(LocaleId localeId) { if (getMissingLocaleVersionMap().containsKey(localeId)) { return getMissingLocaleVersionMap().get(localeId); } - return Lists.newArrayList(); + return Collections.EMPTY_LIST; } public String getMissingVersionTitle(LocaleId localeId) { int size = getMissingVersion(localeId).size(); if (size > 1) { - return zanataMessages.getMessage("jsf.ProjectsMissingLanguage", - size); + return msgs.format("jsf.ProjectsMissingLanguage", size); } - return zanataMessages.getMessage("jsf.ProjectMissingLanguage", size); + return msgs.format("jsf.ProjectMissingLanguage", size); } public boolean isLocaleActivatedInVersion(HProjectIteration version, @@ -541,12 +541,14 @@ public void resetPageData() { projectTabVersionFilter.reset(); languageTabLanguageFilter.reset(); languageTabVersionFilter.reset(); + localeStats.clear(); + projectStats.clear(); loadStatistics(); } @Override protected String getMessage(String key, Object... args) { - return zanataMessages.getMessage(key, args); + return msgs.format(key, args); } public void setSelectedLocaleId(String localeId) { diff --git a/zanata-war/src/main/java/org/zanata/action/VersionGroupJoinAction.java b/zanata-war/src/main/java/org/zanata/action/VersionGroupJoinAction.java index 45eeb6b296..def81c7e88 100644 --- a/zanata-war/src/main/java/org/zanata/action/VersionGroupJoinAction.java +++ b/zanata-war/src/main/java/org/zanata/action/VersionGroupJoinAction.java @@ -31,6 +31,7 @@ import org.apache.commons.lang.StringUtils; import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; @@ -47,6 +48,7 @@ import com.google.common.collect.Lists; +@AutoCreate @Name("versionGroupJoinAction") @Scope(ScopeType.PAGE) public class VersionGroupJoinAction implements Serializable { @@ -139,7 +141,7 @@ public String send() { return sendEmail.sendToVersionGroupMaintainer(maintainers); } else { FacesMessages.instance().add( - "#{messages['jsf.NoProjectVersionSelected']}"); + "#{msgs['jsf.NoProjectVersionSelected']}"); return "failure"; } } diff --git a/zanata-war/src/main/java/org/zanata/action/VersionHome.java b/zanata-war/src/main/java/org/zanata/action/VersionHome.java index 73c95dc1be..5a1a980050 100644 --- a/zanata-war/src/main/java/org/zanata/action/VersionHome.java +++ b/zanata-war/src/main/java/org/zanata/action/VersionHome.java @@ -21,6 +21,7 @@ */ package org.zanata.action; +import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -31,6 +32,7 @@ import javax.faces.event.ValueChangeEvent; import javax.persistence.EntityNotFoundException; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -48,6 +50,8 @@ import org.zanata.common.LocaleId; import org.zanata.common.ProjectType; import org.zanata.dao.ProjectDAO; +import org.zanata.dao.ProjectIterationDAO; +import org.zanata.i18n.Messages; import org.zanata.model.HLocale; import org.zanata.model.HProject; import org.zanata.model.HProjectIteration; @@ -57,11 +61,12 @@ import org.zanata.service.ValidationService; import org.zanata.ui.autocomplete.LocaleAutocomplete; import org.zanata.util.ComparatorUtil; -import org.zanata.util.ZanataMessages; import org.zanata.webtrans.shared.model.ValidationAction; import org.zanata.webtrans.shared.model.ValidationId; import org.zanata.webtrans.shared.validation.ValidationFactory; +import com.google.common.base.Function; +import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -82,6 +87,9 @@ public class VersionHome extends SlugHome { @Setter private String projectSlug; + @In + private ProjectIterationDAO projectIterationDAO; + @In private ConversationScopeMessages conversationScopeMessages; @@ -98,7 +106,10 @@ public class VersionHome extends SlugHome { private ProjectDAO projectDAO; @In - private ZanataMessages zanataMessages; + private Messages msgs; + + @In + private CopyVersionManager copyVersionManager; private Map availableValidations = Maps .newHashMap(); @@ -115,16 +126,57 @@ public class VersionHome extends SlugHome { private VersionLocaleAutocomplete localeAutocomplete = new VersionLocaleAutocomplete(); + @Getter + private boolean copyFromVersion; + + @Getter + @Setter + private String copyFromVersionSlug; + + private final Function VERSION_ITEM_FN = + new Function() { + @Override + public VersionItem apply(HProjectIteration input) { + boolean selected = StringUtils.isNotEmpty( + copyFromVersionSlug) && copyFromVersionSlug + .equals(input.getSlug()) ? true : false; + return new VersionItem(selected, input); + } + }; + + public void setCopyFromVersion(boolean copyFromVersion) { + this.copyFromVersion = copyFromVersion; + List otherVersions = getOtherVersions(); + if (!otherVersions.isEmpty()) { + this.copyFromVersionSlug = + otherVersions.get(0).getVersion().getSlug(); + } else { + this.copyFromVersionSlug = ""; + } + } + + public void reset() { + slug = null; + copyFromVersionSlug = null; + clearInstance(); + } + public void init(boolean isNewInstance) { this.isNewInstance = isNewInstance; if (isNewInstance) { - ProjectType projectType = getProject().getDefaultProjectType(); - if (projectType != null) { - selectedProjectType = projectType.name(); + // set copy from version option to true + if (StringUtils.isNotEmpty(copyFromVersionSlug)) { + copyFromVersion = true; + } else { + ProjectType projectType = getProject().getDefaultProjectType(); + if (projectType != null) { + selectedProjectType = projectType.name(); + } } + } else { ProjectType versionProjectType = getInstance().getProjectType(); - if(versionProjectType != null) { + if (versionProjectType != null) { selectedProjectType = versionProjectType.name(); } } @@ -134,6 +186,36 @@ public HProject getProject() { return projectDAO.getBySlug(projectSlug); } + public List getOtherVersions() { + HProject project = getProject(); + if (project != null) { + List versionList = + projectIterationDAO.getByProjectSlug(projectSlug, + EntityStatus.ACTIVE, EntityStatus.READONLY); + + Collections.sort(versionList, + ComparatorUtil.VERSION_CREATION_DATE_COMPARATOR); + + List versionItems = + Lists.transform(versionList, VERSION_ITEM_FN); + + if (StringUtils.isEmpty(copyFromVersionSlug) + && !versionItems.isEmpty()) { + versionItems.get(0).setSelected(true); + } + return versionItems; + } + return Collections.EMPTY_LIST; + } + + @Getter + @Setter + @AllArgsConstructor + public class VersionItem implements Serializable { + private boolean selected; + private HProjectIteration version; + } + @Restrict("#{s:hasPermission(versionHome.instance, 'update')}") public void updateCustomisedLocales(String key, boolean checked) { getInstance().setOverrideLocales(!checked); @@ -154,12 +236,11 @@ public void updateRequireTranslationReview(String key, boolean checked) { update(); if (checked) { conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages - .getMessage("jsf.iteration.requireReview.enabled")); + msgs.get("jsf.iteration.requireReview.enabled")); } else { conversationScopeMessages - .setMessage(FacesMessage.SEVERITY_INFO, zanataMessages - .getMessage("jsf.iteration.requireReview.disabled")); + .setMessage(FacesMessage.SEVERITY_INFO, + msgs.get("jsf.iteration.requireReview.disabled")); } } @@ -230,25 +311,50 @@ public boolean isSlugAvailable(String slug) { projectSlug); } + public String createVersion() { + if (!validateSlug(getInstance().getSlug(), "slug")) + return "invalid-slug"; + + if (copyFromVersion) { + copyVersion(); + return "copy-version"; + } else { + return persist(); + } + } + + public void copyVersion() { + getInstance().setStatus(EntityStatus.READONLY); + + // create basic version here + HProject project = getProject(); + project.addIteration(getInstance()); + super.persist(); + + copyVersionManager.startCopyVersion(projectSlug, + copyFromVersionSlug, getInstance().getSlug()); + + conversationScopeMessages + .setMessage(FacesMessage.SEVERITY_INFO, msgs. + format("jsf.copyVersion.started", + getInstance().getSlug(), copyFromVersionSlug)); + } + @Override public String persist() { - conversationScopeMessages.clearMessages(); updateProjectType(); - if (!validateSlug(getInstance().getSlug(), "slug")) - return null; - HProject project = getProject(); project.addIteration(getInstance()); List projectLocales = - localeServiceImpl.getSupportedLanguageByProject(projectSlug); + localeServiceImpl + .getSupportedLanguageByProject(projectSlug); getInstance().getCustomizedLocales().addAll(projectLocales); getInstance().getCustomizedValidations().putAll( project.getCustomizedValidations()); - return super.persist(); } @@ -299,14 +405,13 @@ public void copyValidationFromProject() { conversationScopeMessages .setMessage( FacesMessage.SEVERITY_INFO, - zanataMessages - .getMessage("jsf.iteration.CopyProjectValidations.message")); + msgs.get( + "jsf.iteration.CopyProjectValidations.message")); } @Override @Restrict("#{s:hasPermission(versionHome.instance, 'update')}") public String update() { - conversationScopeMessages.clearMessages(); String state = super.update(); Events.instance().raiseEvent(PROJECT_ITERATION_UPDATE, getInstance()); return state; @@ -333,7 +438,7 @@ public void removeLanguage(LocaleId localeId) { update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.iteration.LanguageRemoved", + msgs.format("jsf.iteration.LanguageRemoved", locale.retrieveDisplayName())); } @@ -342,7 +447,7 @@ public void updateStatus(char initial) { getInstance().setStatus(EntityStatus.valueOf(initial)); update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.iteration.status.updated", + msgs.format("jsf.iteration.status.updated", EntityStatus.valueOf(initial))); } @@ -356,8 +461,15 @@ public void copyProjectTypeFromProject() { getInstance().getProject().getDefaultProjectType()); update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages - .getMessage("jsf.iteration.CopyProjectType.message")); + msgs.get("jsf.iteration.CopyProjectType.message")); + } + + /** + * @return comma-separated list of accepted file extensions. May be an empty string + */ + public String getAcceptedSourceFileTypes() { + return Joiner.on(", ") + .join(ProjectType.getSupportedSourceFileTypes(getProjectType())); } private void updateProjectType() { @@ -392,7 +504,7 @@ public void updateValidationOption(String name, String state) { } update(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.validation.updated", + msgs.format("jsf.validation.updated", validatationId.getDisplayName(), state)); } @@ -425,7 +537,7 @@ protected Collection getLocales() { .getSupportedLanguageByProjectIteration(projectSlug, slug); } - return Lists.newArrayList(); + return Collections.EMPTY_LIST; } /** @@ -443,7 +555,7 @@ public void onSelectItemAction() { update(conversationScopeMessages); reset(); conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, - zanataMessages.getMessage("jsf.iteration.LanguageAdded", + msgs.format("jsf.iteration.LanguageAdded", locale.retrieveDisplayName())); } diff --git a/zanata-war/src/main/java/org/zanata/action/VersionHomeAction.java b/zanata-war/src/main/java/org/zanata/action/VersionHomeAction.java index c4a12aa057..5ee534bf38 100644 --- a/zanata-war/src/main/java/org/zanata/action/VersionHomeAction.java +++ b/zanata-war/src/main/java/org/zanata/action/VersionHomeAction.java @@ -28,16 +28,17 @@ import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.security.Restrict; import org.jboss.seam.util.Hex; +import org.zanata.async.tasks.CopyVersionTask; import org.zanata.common.DocumentType; import org.zanata.common.EntityStatus; import org.zanata.common.LocaleId; @@ -50,6 +51,7 @@ import org.zanata.exception.ZanataServiceException; import org.zanata.file.FilePersistService; import org.zanata.file.GlobalDocumentId; +import org.zanata.i18n.Messages; import org.zanata.model.HDocument; import org.zanata.model.HIterationGroup; import org.zanata.model.HLocale; @@ -71,11 +73,12 @@ import org.zanata.ui.AbstractListFilter; import org.zanata.ui.AbstractSortAction; import org.zanata.ui.InMemoryListFilter; +import org.zanata.ui.ProgressBar; import org.zanata.ui.model.statistic.WordStatistic; import org.zanata.util.DateUtil; +import org.zanata.util.ServiceLocator; import org.zanata.util.StatisticsUtil; import org.zanata.util.UrlUtil; -import org.zanata.util.ZanataMessages; import org.zanata.webtrans.shared.model.DocumentStatus; import javax.faces.application.FacesMessage; @@ -100,6 +103,9 @@ public class VersionHomeAction extends AbstractSortAction implements Serializable { private static final long serialVersionUID = 1L; + @In + private CopyVersionManager copyVersionManager; + @In private ProjectIterationDAO projectIterationDAO; @@ -116,7 +122,7 @@ public class VersionHomeAction extends AbstractSortAction implements private DocumentStateCache documentStateCacheImpl; @In - private ZanataMessages zanataMessages; + private Messages msgs; @In private DocumentService documentServiceImpl; @@ -136,11 +142,9 @@ public class VersionHomeAction extends AbstractSortAction implements @In private TranslationService translationServiceImpl; - @Setter @Getter private String versionSlug; - @Setter @Getter private String projectSlug; @@ -185,18 +189,24 @@ public class VersionHomeAction extends AbstractSortAction implements @Getter private SortingType documentSortingList = new SortingType( Lists.newArrayList(SortingType.SortOption.ALPHABETICAL, + SortingType.SortOption.HOURS, + SortingType.SortOption.PERCENTAGE, + SortingType.SortOption.WORDS, SortingType.SortOption.LAST_SOURCE_UPDATE, SortingType.SortOption.LAST_TRANSLATED)); @Getter private SortingType sourceDocumentSortingList = new SortingType( Lists.newArrayList(SortingType.SortOption.ALPHABETICAL, + SortingType.SortOption.HOURS, + SortingType.SortOption.PERCENTAGE, + SortingType.SortOption.WORDS, SortingType.SortOption.LAST_SOURCE_UPDATE)); @Getter private SortingType settingsDocumentSortingList = new SortingType( Lists.newArrayList(SortingType.SortOption.ALPHABETICAL, - SortingType.SortOption.LAST_SOURCE_UPDATE)); + SortingType.SortOption.LAST_SOURCE_UPDATE)); private final LanguageComparator languageComparator = new LanguageComparator(getLanguageSortingList()); @@ -222,6 +232,9 @@ public class VersionHomeAction extends AbstractSortAction implements private final DocumentFilter languageTabDocumentFilter = new DocumentFilter(); + @Getter + private CopyVersionHandler copyVersionHandler = new CopyVersionHandler(); + @Getter private final AbstractListFilter groupFilter = new InMemoryListFilter() { @@ -233,7 +246,7 @@ protected List fetchAll() { @Override protected boolean include(HIterationGroup elem, String filter) { return StringUtils.containsIgnoreCase(elem.getName(), - filter) + filter) || StringUtils.containsIgnoreCase(elem.getSlug(), filter); } @@ -273,6 +286,85 @@ protected boolean include(HLocale elem, String filter) { } }; + public void setVersionSlug(String versionSlug) { + this.versionSlug = versionSlug; + copyVersionHandler.setVersionSlug(versionSlug); + } + + public void setProjectSlug(String projectSlug) { + this.projectSlug = projectSlug; + copyVersionHandler.setProjectSlug(projectSlug); + } + + public void onCopyVersionComplete() { + conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, + msgs.format("jsf.copyVersion.Completed", versionSlug)); + } + + public void cancelCopyVersion() { + copyVersionManager.cancelCopyVersion(projectSlug, versionSlug); + conversationScopeMessages.setMessage(FacesMessage.SEVERITY_INFO, + msgs.format("jsf.copyVersion.Cancelled", versionSlug)); + } + + @NoArgsConstructor + public static class CopyVersionHandler implements ProgressBar { + + @Setter + private String projectSlug; + + @Setter + private String versionSlug; + + @Override + public boolean isInProgress() { + return getCopyVersionManager().isCopyVersionRunning(projectSlug, + versionSlug); + } + + @Override + public String getCompletedPercentage() { + CopyVersionTask.CopyVersionTaskHandle handle = getHandle(); + if (handle != null) { + double completedPercent = + (double) handle.getCurrentProgress() / (double) handle + .getMaxProgress() * 100; + return PERCENT_FORMAT.format(completedPercent); + } else { + return "0"; + } + } + + public int getProcessedDocuments() { + CopyVersionTask.CopyVersionTaskHandle handle = getHandle(); + if (handle != null) { + return handle.getDocumentCopied(); + } + return 0; + } + + public int getTotalDocuments() { + CopyVersionTask.CopyVersionTaskHandle handle = getHandle(); + if (handle != null) { + return handle.getTotalDoc(); + } + return 0; + } + + private CopyVersionManager getCopyVersionManager() { + return ServiceLocator.instance().getInstance( + CopyVersionManager.class); + } + + private CopyVersionTask.CopyVersionTaskHandle getHandle() { + CopyVersionManager copyVersionManager = ServiceLocator + .instance().getInstance(CopyVersionManager.class); + + return copyVersionManager.getCopyVersionProcessHandle(projectSlug, + versionSlug); + } + } + /** * Sort language list based on locale statistic */ @@ -351,7 +443,7 @@ protected void loadStatistics() { @Override protected String getMessage(String key, Object... args) { - return zanataMessages.getMessage(key, args); + return msgs.format(key, args); } public List getSupportedLocale() { @@ -364,6 +456,13 @@ public List getSupportedLocale() { return supportedLocale; } + public int + getVersionSupportedLocaleCount(String projectSlug, + String versionSlug) { + return localeServiceImpl.getSupportedLanguageByProjectIteration( + projectSlug, versionSlug).size(); + } + public List getDocuments() { if (documents == null) { documents = @@ -561,18 +660,17 @@ public String getZipFileDownloadTitle() { if (!isZipFileDownloadAllowed()) { if (getVersion().getProjectType() == null) { message = - zanataMessages - .getMessage("jsf.iteration.files.DownloadAllFiles.ProjectTypeNotSet"); + msgs.get( + "jsf.iteration.files.DownloadAllFiles.ProjectTypeNotSet"); } else if (getVersion().getProjectType() != ProjectType.Gettext && getVersion().getProjectType() != ProjectType.Podir) { message = - zanataMessages - .getMessage("jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed"); + msgs.get( + "jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed"); } } else { message = - zanataMessages - .getMessage("jsf.iteration.files.DownloadAll"); + msgs.get("jsf.iteration.files.DownloadAll"); } return message; } @@ -869,8 +967,8 @@ public void uploadTranslationFile(HLocale hLocale) { } private class DocumentFilter extends InMemoryListFilter { - private DocumentDAO documentDAO = (DocumentDAO) Component - .getInstance(DocumentDAO.class); + private DocumentDAO documentDAO = + ServiceLocator.instance().getInstance(DocumentDAO.class); @Override protected List fetchAll() { @@ -885,7 +983,7 @@ protected boolean include(HDocument elem, String filter) { }; private class SourceDocumentFilter extends InMemoryListFilter { - private DocumentDAO documentDAO = (DocumentDAO) Component + private DocumentDAO documentDAO = ServiceLocator.instance() .getInstance(DocumentDAO.class); @Override @@ -933,7 +1031,6 @@ public int compare(HDocument o1, HDocument o2) { DocumentStatus docStat1 = documentStateCacheImpl.getDocumentStatus( o1.getId(), selectedLocaleId); - DocumentStatus docStat2 = documentStateCacheImpl.getDocumentStatus( o2.getId(), selectedLocaleId); diff --git a/zanata-war/src/main/java/org/zanata/action/validator/DuplicateEmailValidator.java b/zanata-war/src/main/java/org/zanata/action/validator/DuplicateEmailValidator.java index 0adffba16d..693572ff54 100644 --- a/zanata-war/src/main/java/org/zanata/action/validator/DuplicateEmailValidator.java +++ b/zanata-war/src/main/java/org/zanata/action/validator/DuplicateEmailValidator.java @@ -25,9 +25,8 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; import org.zanata.dao.PersonDAO; +import org.zanata.util.ServiceLocator; public class DuplicateEmailValidator implements ConstraintValidator, Serializable { @@ -40,8 +39,7 @@ public boolean isValid(String string, ConstraintValidatorContext context) { if (string.length() == 0) return true; PersonDAO personDAO = - (PersonDAO) Component.getInstance(PersonDAO.class, - ScopeType.STATELESS); + ServiceLocator.instance().getInstance(PersonDAO.class); return personDAO.findByEmail(string) == null; } diff --git a/zanata-war/src/main/java/org/zanata/action/validator/NotDuplicateEmail.java b/zanata-war/src/main/java/org/zanata/action/validator/NotDuplicateEmail.java index 7d03d6325a..248418c368 100644 --- a/zanata-war/src/main/java/org/zanata/action/validator/NotDuplicateEmail.java +++ b/zanata-war/src/main/java/org/zanata/action/validator/NotDuplicateEmail.java @@ -36,7 +36,7 @@ public @interface NotDuplicateEmail { Class[] groups() default {}; - String message() default "{javax.validation.constraints.NotDuplicateEmail.messag}"; + String message() default "{javax.validation.constraints.NotDuplicateEmail.message}"; Class[] payload() default {}; } diff --git a/zanata-war/src/main/java/org/zanata/adapter/SubtitleAdapter.java b/zanata-war/src/main/java/org/zanata/adapter/SubtitleAdapter.java new file mode 100644 index 0000000000..9c1598a26d --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/adapter/SubtitleAdapter.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ + +package org.zanata.adapter; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import net.sf.okapi.common.IParameters; +import net.sf.okapi.filters.regex.RegexFilter; + +import java.io.IOException; +import java.net.URL; + +/** + * Adapter to handle Sub-Rip Text (.srt), WebVTT (.vtt) and SubViewer (.sbv/sub) + * subtitle files.
+ * It uses the Okapi's {@link net.sf.okapi.filters.regex.RegexFilter} class + * with a regex specific to these formats.
+ * + * @see + * SubRip Text Specification + * @see WebVTT Specification + * + * @author Damian Jansen + * djansen@redhat.com + */ +public class SubtitleAdapter extends OkapiFilterAdapter { + + private static final String defaultConfig = loadDefaultConfig(); + + private static String loadDefaultConfig() { + URL configURL = SubtitleAdapter.class + .getResource("SubtitleAdapterDefaultConfiguration.yml"); + try { + return Resources.toString(configURL, Charsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException( + "Failed to load default config for SRT adapter.", e); + } + } + + public SubtitleAdapter() { + super(prepareFilter(), IdSource.textUnitName, true); + } + + private static RegexFilter prepareFilter() { + return new RegexFilter(); + } + + @Override + protected void updateParamsWithDefaults(IParameters params) { + params.fromString(defaultConfig); + } +} diff --git a/zanata-war/src/main/java/org/zanata/async/AsyncTask.java b/zanata-war/src/main/java/org/zanata/async/AsyncTask.java index 9abd50b0fc..a319201a41 100644 --- a/zanata-war/src/main/java/org/zanata/async/AsyncTask.java +++ b/zanata-war/src/main/java/org/zanata/async/AsyncTask.java @@ -20,6 +20,7 @@ */ package org.zanata.async; +import javax.annotation.Nonnull; import java.util.concurrent.Callable; /** @@ -40,6 +41,6 @@ public interface AsyncTask> extends Callable * @return The handle used to keep task information. Tasks must always * return the same instance of a handle. */ - H getHandle(); + @Nonnull H getHandle(); } diff --git a/zanata-war/src/main/java/org/zanata/async/AsynchronousTaskExecutor.java b/zanata-war/src/main/java/org/zanata/async/AsynchronousTaskExecutor.java index 46c08432a9..6a072a4236 100644 --- a/zanata-war/src/main/java/org/zanata/async/AsynchronousTaskExecutor.java +++ b/zanata-war/src/main/java/org/zanata/async/AsynchronousTaskExecutor.java @@ -25,7 +25,6 @@ import javax.security.auth.Subject; import com.google.common.util.concurrent.MoreExecutors; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Name; @@ -38,6 +37,7 @@ import org.zanata.dao.AccountDAO; import org.zanata.model.HAccount; import org.zanata.security.ZanataJpaIdentityStore; +import org.zanata.util.ServiceLocator; /** * This class executes a Runnable Process asynchronously. Do not use this class @@ -112,15 +112,14 @@ private static void prepareSecurityContext(String username) { // Only if it's an authenticated task should it try and do this // injection AccountDAO accountDAO = - (AccountDAO) Component.getInstance(AccountDAO.class); + ServiceLocator.instance().getInstance(AccountDAO.class); ZanataJpaIdentityStore idStore = - (ZanataJpaIdentityStore) Component - .getInstance(ZanataJpaIdentityStore.class); + ServiceLocator.instance().getInstance( + ZanataJpaIdentityStore.class); AuthenticationEvents authEvts = - (AuthenticationEvents) Component - .getInstance(AuthenticationEvents.class); + ServiceLocator.instance().getInstance( + AuthenticationEvents.class); HAccount authenticatedAccount = accountDAO.getByUsername(username); - authEvts.injectAuthenticatedPersonIntoWorkingMemory(authenticatedAccount); idStore.setAuthenticateUser(authenticatedAccount); } } diff --git a/zanata-war/src/main/java/org/zanata/async/SimpleAsyncTask.java b/zanata-war/src/main/java/org/zanata/async/SimpleAsyncTask.java index bc071ad96e..e7bb8d8b3a 100644 --- a/zanata-war/src/main/java/org/zanata/async/SimpleAsyncTask.java +++ b/zanata-war/src/main/java/org/zanata/async/SimpleAsyncTask.java @@ -22,6 +22,8 @@ import lombok.Getter; +import javax.annotation.Nonnull; + /** * Simple default partial implementation of an async task that produces a bare * bones {@link AsyncTaskHandle} that tracks progress. @@ -32,10 +34,10 @@ public abstract class SimpleAsyncTask implements AsyncTask> { @Getter + @Nonnull private final AsyncTaskHandle handle; public SimpleAsyncTask(String taskName) { handle = new AsyncTaskHandle(taskName); } - } diff --git a/zanata-war/src/main/java/org/zanata/async/TaskExecutor.java b/zanata-war/src/main/java/org/zanata/async/TaskExecutor.java index 0eb913c959..5fc22b3f3b 100644 --- a/zanata-war/src/main/java/org/zanata/async/TaskExecutor.java +++ b/zanata-war/src/main/java/org/zanata/async/TaskExecutor.java @@ -27,6 +27,8 @@ import org.jboss.seam.annotations.Scope; import org.jboss.seam.security.Identity; +import javax.annotation.Nonnull; + /** * This component executes {@link org.zanata.async.AsyncTask} instances. It is * generally more advisable to use the @@ -54,13 +56,8 @@ public class TaskExecutor { * If the provided task value is null. */ public > AsyncTaskHandle startTask( - AsyncTask task, Runnable onComplete) { + @Nonnull AsyncTask task, Runnable onComplete) { H handle = task.getHandle(); - if (handle == null) { - throw new RuntimeException( - "An Asynchronous task should always return a non-null handle"); - } - Identity identity = Identity.instance(); asynchronousTaskExecutor.runAsynchronously(task, onComplete, identity .getPrincipal(), identity.getSubject(), diff --git a/zanata-war/src/main/java/org/zanata/async/tasks/CopyTransTask.java b/zanata-war/src/main/java/org/zanata/async/tasks/CopyTransTask.java index f0d75e2bc4..10b6578c66 100644 --- a/zanata-war/src/main/java/org/zanata/async/tasks/CopyTransTask.java +++ b/zanata-war/src/main/java/org/zanata/async/tasks/CopyTransTask.java @@ -27,6 +27,9 @@ import org.zanata.model.HCopyTransOptions; import org.zanata.security.ZanataIdentity; +import javax.annotation.Nonnull; +import java.io.IOException; + /** * Asynchronous Task that runs copy trans. Subclasses should allow for running * copy trans against different targets. @@ -46,6 +49,7 @@ public CopyTransTask(HCopyTransOptions copyTransOptions, String taskName) { this.handle = new CopyTransTaskHandle(taskName); } + @Nonnull @Override public CopyTransTaskHandle getHandle() { return handle; diff --git a/zanata-war/src/main/java/org/zanata/async/tasks/CopyVersionTask.java b/zanata-war/src/main/java/org/zanata/async/tasks/CopyVersionTask.java new file mode 100644 index 0000000000..b7fae529ae --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/async/tasks/CopyVersionTask.java @@ -0,0 +1,100 @@ +package org.zanata.async.tasks; + +import javax.annotation.Nonnull; + +import org.zanata.async.AsyncTask; +import org.zanata.async.TimedAsyncHandle; +import org.zanata.security.ZanataIdentity; +import org.zanata.service.CopyVersionService; +import org.zanata.service.impl.CopyVersionServiceImpl; +import org.zanata.util.ServiceLocator; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author Alex Eng aeng@redhat.com + */ + +public class CopyVersionTask implements + AsyncTask { + + private final CopyVersionTaskHandle handle; + + private final String projectSlug; + private final String versionSlug; + private final String newVersionSlug; + + public CopyVersionTask(String projectSlug, String versionSlug, + String newVersionSlug) { + handle = + new CopyVersionTaskHandle("VersionCopyTask:" + versionSlug + + ":" + newVersionSlug); + this.projectSlug = projectSlug; + this.versionSlug = versionSlug; + this.newVersionSlug = newVersionSlug; + } + + /** + * @return The maximum progress for the copy version task. (total document + * to be copied) + */ + protected int getMaxProgress() { + CopyVersionService copyVersionServiceImpl = + ServiceLocator.instance().getInstance( + CopyVersionServiceImpl.class); + + return copyVersionServiceImpl.getTotalDocCount( + projectSlug, versionSlug); + } + + protected void runCopyVersion() { + CopyVersionService copyVersionServiceImpl = + ServiceLocator.instance().getInstance( + CopyVersionServiceImpl.class); + copyVersionServiceImpl.copyVersion(projectSlug, versionSlug, + newVersionSlug); + } + + @Override + public Void call() throws Exception { + getHandle().startTiming(); + getHandle() + .setTriggeredBy(ZanataIdentity.instance().getAccountUsername()); + getHandle().setMaxProgress(getMaxProgress()); + getHandle().setTotalDoc(getMaxProgress()); + + runCopyVersion(); + + getHandle().finishTiming(); + return null; + } + + @Nonnull + @Override + public CopyVersionTaskHandle getHandle() { + return handle; + } + + @Getter + @Setter + public static class CopyVersionTaskHandle extends TimedAsyncHandle { + private int documentCopied; + private int totalDoc; + private String cancelledBy; + private long cancelledTime; + private String triggeredBy; + + public CopyVersionTaskHandle(String taskName) { + super(taskName); + } + + /** + * Increments the processed task by 1 + */ + public void incrementDocumentProcessed() { + documentCopied++; + } + + } +} diff --git a/zanata-war/src/main/java/org/zanata/async/tasks/IterationCopyTransTask.java b/zanata-war/src/main/java/org/zanata/async/tasks/IterationCopyTransTask.java index 78c8dc0067..5812985576 100644 --- a/zanata-war/src/main/java/org/zanata/async/tasks/IterationCopyTransTask.java +++ b/zanata-war/src/main/java/org/zanata/async/tasks/IterationCopyTransTask.java @@ -80,8 +80,8 @@ protected int getMaxProgress() { @Override protected void callCopyTrans() { CopyTransService copyTransServiceImpl = - (CopyTransService) Component - .getInstance(CopyTransServiceImpl.class); + ServiceLocator.instance().getInstance( + CopyTransServiceImpl.class); copyTransServiceImpl.copyTransForIteration(projectIteration, copyTransOptions); } diff --git a/zanata-war/src/main/java/org/zanata/async/tasks/ZipFileBuildTask.java b/zanata-war/src/main/java/org/zanata/async/tasks/ZipFileBuildTask.java index 11c3f1178f..c71c9fa187 100644 --- a/zanata-war/src/main/java/org/zanata/async/tasks/ZipFileBuildTask.java +++ b/zanata-war/src/main/java/org/zanata/async/tasks/ZipFileBuildTask.java @@ -28,7 +28,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.jboss.seam.Component; import org.zanata.adapter.po.PoWriter2; import org.zanata.async.AsyncTask; import org.zanata.async.AsyncTaskHandle; @@ -48,6 +47,9 @@ import org.zanata.service.impl.FileSystemServiceImpl; import com.google.common.base.Optional; +import org.zanata.util.ServiceLocator; + +import javax.annotation.Nonnull; /** * This is an asynchronous task to build a zip file containing all files for a @@ -77,6 +79,7 @@ public ZipFileBuildTask(String projectSlug, String iterationSlug, this.isPoProject = isPoProject; } + @Nonnull @Override public AsyncTaskHandle getHandle() { if (handle == null) { @@ -91,7 +94,7 @@ private AsyncTaskHandle buildHandle() { // Max documents to process DocumentDAO documentDAO = - (DocumentDAO) Component.getInstance(DocumentDAO.class); + ServiceLocator.instance().getInstance(DocumentDAO.class); final List allIterationDocs = documentDAO .getAllByProjectIteration(projectSlug, iterationSlug); @@ -106,20 +109,19 @@ private AsyncTaskHandle buildHandle() { public String call() throws Exception { // Needed Components DocumentDAO documentDAO = - (DocumentDAO) Component.getInstance(DocumentDAO.class); + ServiceLocator.instance().getInstance(DocumentDAO.class); LocaleDAO localeDAO = - (LocaleDAO) Component.getInstance(LocaleDAO.class); + ServiceLocator.instance().getInstance(LocaleDAO.class); ResourceUtils resourceUtils = - (ResourceUtils) Component.getInstance(ResourceUtils.class); + ServiceLocator.instance().getInstance(ResourceUtils.class); TextFlowTargetDAO textFlowTargetDAO = - (TextFlowTargetDAO) Component - .getInstance(TextFlowTargetDAO.class); + ServiceLocator.instance().getInstance(TextFlowTargetDAO.class); FileSystemService fileSystemService = - (FileSystemService) Component - .getInstance(FileSystemServiceImpl.class); + ServiceLocator.instance().getInstance( + FileSystemServiceImpl.class); ConfigurationService configurationService = - (ConfigurationService) Component - .getInstance(ConfigurationServiceImpl.class); + ServiceLocator.instance().getInstance( + ConfigurationServiceImpl.class); final String projectDirectory = projectSlug + "-" + iterationSlug + "/"; final HLocale hLocale = diff --git a/zanata-war/src/main/java/org/zanata/config/DatabaseBackedConfig.java b/zanata-war/src/main/java/org/zanata/config/DatabaseBackedConfig.java index 14f740c6e8..187732eab9 100644 --- a/zanata-war/src/main/java/org/zanata/config/DatabaseBackedConfig.java +++ b/zanata-war/src/main/java/org/zanata/config/DatabaseBackedConfig.java @@ -24,7 +24,6 @@ import java.util.HashMap; import java.util.Map; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Create; @@ -165,4 +164,8 @@ public String getMaxConcurrentRequestsPerApiKey() { public String getMaxActiveRequestsPerApiKey() { return getConfigValue(HApplicationConfiguration.KEY_MAX_ACTIVE_REQ_PER_API_KEY); } + + public String getMaxFilesPerUpload() { + return getConfigValue(HApplicationConfiguration.KEY_MAX_FILES_PER_UPLOAD); + } } diff --git a/zanata-war/src/main/java/org/zanata/dao/DocumentDAO.java b/zanata-war/src/main/java/org/zanata/dao/DocumentDAO.java index ca8d87e4e2..c5786fa327 100644 --- a/zanata-war/src/main/java/org/zanata/dao/DocumentDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/DocumentDAO.java @@ -467,6 +467,39 @@ public List getByProjectIteration(final String projectSlug, return q.list(); } + public List findAllByVersionId(Long versionId, int offset, + int maxResults) { + Query q = + getSession() + .createQuery( + "from HDocument doc where doc.obsolete=0 and doc.projectIteration.id = :versionId"); + q.setParameter("versionId", versionId); + q.setFirstResult(offset); + q.setMaxResults(maxResults); + q.setCacheable(true).setComment("DocumentDAO.getDocByVersionId"); + return q.list(); + } + + public int getDocCountByVersion(String projectSlug, String versionSlug) { + Long totalCount = + (Long) getSession() + .createQuery( + "select count(doc) from HDocument doc " + + + "where doc.obsolete=0 and doc.projectIteration.slug = :versionSlug " + + + "and doc.projectIteration.project.slug = :projectSlug") + .setParameter("versionSlug", versionSlug) + .setParameter("projectSlug", projectSlug) + .setComment("DocumentDAO.getDocCountByVersion") + .setCacheable(true).uniqueResult(); + + if (totalCount == null) { + totalCount = 0L; + } + return totalCount.intValue(); + } + /** * Calculates a translated document's hash. * diff --git a/zanata-war/src/main/java/org/zanata/dao/PersonDAO.java b/zanata-war/src/main/java/org/zanata/dao/PersonDAO.java index b544240adf..9f9ee5e3d1 100644 --- a/zanata-war/src/main/java/org/zanata/dao/PersonDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/PersonDAO.java @@ -113,8 +113,10 @@ public List findAllContainingName(String name) { Query query = getSession() .createQuery( - "from HPerson as p where p.account.username like :name or p.name like :name"); - query.setParameter("name", "%" + name + "%"); + "from HPerson as p " + + "where lower(p.account.username) like :name " + + "or lower(p.name) like :name"); + query.setParameter("name", "%" + name.toLowerCase() + "%"); query.setCacheable(false); query.setComment("PersonDAO.findAllContainingName"); return query.list(); diff --git a/zanata-war/src/main/java/org/zanata/dao/ProjectDAO.java b/zanata-war/src/main/java/org/zanata/dao/ProjectDAO.java index 4e4abc2193..f4b66cf36b 100644 --- a/zanata-war/src/main/java/org/zanata/dao/ProjectDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/ProjectDAO.java @@ -2,17 +2,19 @@ import java.util.Date; import java.util.List; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; +import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.index.Term; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.TermQuery; +import org.apache.lucene.util.Version; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.search.jpa.FullTextEntityManager; @@ -262,14 +264,35 @@ public int getQueryProjectSize(@Nonnull String searchQuery, return query.getResultSize(); } - private FullTextQuery getTextQuery(@Nonnull String searchQuery, - boolean includeObsolete) { - searchQuery = QueryParser.escape(searchQuery.toLowerCase()); + private org.apache.lucene.search.Query constructQuery(String field, String searchQuery) + throws ParseException { + QueryParser parser = + new QueryParser(Version.LUCENE_29, field, + new StandardAnalyzer(Version.LUCENE_29)); + return parser.parse(searchQuery); + } + + /** + * Lucene index for project name and slug replaces hyphen with + * space. This method is to replace hyphen with space when performing search + * + * @param query + * @return + */ + private String parseSlugAndName(String query) { + return query.replace("-", " "); + } - PrefixQuery slugQuery = new PrefixQuery(new Term("slug", searchQuery)); - PrefixQuery nameQuery = new PrefixQuery(new Term("name", searchQuery)); - PrefixQuery descQuery = - new PrefixQuery(new Term("description", searchQuery)); + private FullTextQuery getTextQuery(@Nonnull String searchQuery, + boolean includeObsolete) throws ParseException { + org.apache.lucene.search.Query nameQuery = + constructQuery("name", parseSlugAndName(searchQuery) + "*"); + org.apache.lucene.search.Query slugQuery = + constructQuery("slug", parseSlugAndName(searchQuery) + "*"); + + searchQuery = QueryParser.escape(searchQuery); + org.apache.lucene.search.Query descQuery = + constructQuery("description", searchQuery); BooleanQuery booleanQuery = new BooleanQuery(); booleanQuery.add(slugQuery, BooleanClause.Occur.SHOULD); diff --git a/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java b/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java index 684057eeeb..bef849a85a 100644 --- a/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/ProjectIterationDAO.java @@ -21,6 +21,7 @@ package org.zanata.dao; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,6 +51,8 @@ import org.zanata.util.HashUtil; import org.zanata.util.StatisticsUtil; +import com.google.common.collect.Lists; + @Name("projectIterationDAO") @AutoCreate @Scope(ScopeType.STATELESS) @@ -84,6 +87,32 @@ public HProjectIteration getBySlug(@Nonnull HProject project, .using("slug", iterationSlug).using("project", project).load(); } + public List getByProjectSlug( + @Nonnull String projectSlug, EntityStatus... includeStatus) { + if (StringUtils.isEmpty(projectSlug)) { + return Collections.EMPTY_LIST; + } + StringBuilder sb = new StringBuilder(); + sb.append("from HProjectIteration version where "). + append("version.project.slug = :projectSlug "); + + if (includeStatus != null) { + sb.append("and version.status in :includesStatus"); + } + + Query q = getSession().createQuery(sb.toString()); + q.setParameter("projectSlug", projectSlug); + + if (includeStatus != null) { + q.setParameterList("includesStatus", + Lists.newArrayList(includeStatus)); + } + q.setComment("ProjectIterationDAO.getByProjectSlug"); + List results = q.list(); + return results; + + } + public List getByGroup(HIterationGroup group) { Query q = getSession() diff --git a/zanata-war/src/main/java/org/zanata/dao/RawDocumentDAO.java b/zanata-war/src/main/java/org/zanata/dao/RawDocumentDAO.java new file mode 100644 index 0000000000..39db02b458 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/dao/RawDocumentDAO.java @@ -0,0 +1,40 @@ +package org.zanata.dao; + +import org.hibernate.Query; +import org.hibernate.Session; +import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; +import org.zanata.model.HRawDocument; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author Alex Eng aeng@redhat.com + */ +@Name("rawDocumentDAO") +@AutoCreate +@Scope(ScopeType.STATELESS) +@Slf4j +public class RawDocumentDAO extends AbstractDAOImpl { + public RawDocumentDAO() { + super(HRawDocument.class); + } + + public RawDocumentDAO(Session session) { + super(HRawDocument.class, session); + } + + public HRawDocument getByDocumentId(Long docId) { + Query q = + getSession() + .createQuery( + "from HRawDocument rawDoc where rawDoc.document.id = :docId"); + q.setParameter("docId", docId); + q.setCacheable(true); + q.setComment("RawDocumentDAO.getByDocumentId"); + + return (HRawDocument) q.uniqueResult(); + } +} diff --git a/zanata-war/src/main/java/org/zanata/dao/TextFlowDAO.java b/zanata-war/src/main/java/org/zanata/dao/TextFlowDAO.java index 73006a8130..5e4d9daa11 100644 --- a/zanata-war/src/main/java/org/zanata/dao/TextFlowDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/TextFlowDAO.java @@ -92,8 +92,6 @@ public List getNavigationByDocumentId(DocumentId documentId, .setResultTransformer(resultTransformer).list(); } - - public int getTotalWords() { Query q = getSession() @@ -136,36 +134,29 @@ public int countActiveTextFlowsInDocument(Long documentId) { Query q = getSession() .createQuery( - "select count(*) from HTextFlow tf where tf.obsolete=0 and tf.document.id = :id order by tf.pos"); - q.setParameter("id", documentId); - q.setCacheable(true).setComment("TextFlowDAO.countActiveTextFlowsInDocument"); + "select count(*) from HTextFlow tf where tf.obsolete=0 and tf.document.id = :documentId"); + q.setParameter("documentId", documentId); + q.setCacheable(true).setComment( + "TextFlowDAO.countActiveTextFlowsInDocument"); Long totalCount = (Long) q.uniqueResult(); return totalCount == null ? 0 : totalCount.intValue(); } - @SuppressWarnings("unchecked") - public List getTextFlowsByDocumentId(DocumentId documentId, - int startIndex, int maxSize) { + public List getTextFlowsByDocumentId(Long documentId, + Integer offset, Integer maxResults) { Query q = getSession() .createQuery( - "from HTextFlow tf where tf.obsolete=0 and tf.document.id = :id order by tf.pos"); - q.setParameter("id", documentId.getId()); - q.setFirstResult(startIndex); - q.setMaxResults(maxSize); - q.setCacheable(true).setComment("TextFlowDAO.getTextFlowsByDocumentId"); - return q.list(); - } + "from HTextFlow tf where tf.obsolete=0 and tf.document.id = :documentId order by tf.pos"); + q.setParameter("documentId", documentId); - @SuppressWarnings("unchecked") - public List getAllTextFlowsByDocumentId(DocumentId documentId) { - Query q = - getSession() - .createQuery( - "from HTextFlow tf where tf.obsolete=0 and tf.document.id = :id order by tf.pos"); - q.setParameter("id", documentId.getId()); - q.setCacheable(true).setComment( - "TextFlowDAO.getAllTextFlowsByDocumentId"); + if (offset != null) { + q.setFirstResult(offset); + } + if (maxResults != null) { + q.setMaxResults(maxResults); + } + q.setCacheable(true).setComment("TextFlowDAO.getTextFlowsByDocumentId"); return q.list(); } @@ -231,18 +222,16 @@ public List getAllTextFlowByDocumentIdWithConstraints( return result; } - public long countActiveTextFlowsInProjectIteration(Long projIterId) { - Query q = - getSession() - .createQuery( - "select count(*) from HTextFlow tf " + - "where tf.obsolete = 0 and " + - "tf.document.obsolete = 0 and " + - "tf.document.projectIteration.id=:projIterId"); - q.setParameter("projIterId", projIterId); + public long countActiveTextFlowsInProjectIteration(Long versionId) { + String query = + "select count(*) from HTextFlow tf where tf.obsolete = 0 " + + "and tf.document.obsolete = 0 " + + "and tf.document.projectIteration.id=:versionId"; + + Query q = getSession().createQuery(query); + q.setParameter("versionId", versionId); q.setCacheable(true).setComment( "TextFlowDAO.countTextFlowsInProjectIteration"); return (Long) q.uniqueResult(); } - } diff --git a/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetDAO.java b/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetDAO.java index c0cc7588e6..782c8d90f2 100644 --- a/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetDAO.java @@ -2,7 +2,6 @@ import java.util.List; -import com.google.common.base.Optional; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; @@ -21,6 +20,8 @@ import org.zanata.model.HTextFlowTarget; import org.zanata.service.TranslationFinder; +import com.google.common.base.Optional; + @Name("textFlowTargetDAO") @AutoCreate @Scope(ScopeType.STATELESS) @@ -46,6 +47,32 @@ public HTextFlowTarget getByNaturalId(HTextFlow textFlow, HLocale locale) { .using("locale", locale).load(); } + public List getByTextFlowId(Long tfId, int offset, + int maxResults) { + Query q = + getSession() + .createQuery( + "from HTextFlowTarget tft where tft.textFlow.obsolete=0 and tft.textFlow.id = :tfId"); + q.setParameter("tfId", tfId); + q.setFirstResult(offset); + q.setMaxResults(maxResults); + q.setCacheable(true) + .setComment("TextFlowTargetDAO.getByTextFlowId"); + return q.list(); + } + + public int countTextFlowTargetsInTextFlow(Long tfId) { + Query q = + getSession() + .createQuery( + "select count(*) from HTextFlowTarget tft where tft.textFlow.obsolete=0 and tft.textFlow.id = :tfId"); + q.setParameter("tfId", tfId); + q.setCacheable(true).setComment( + "TextFlowTargetDAO.countTextFlowTargetsInTextFlow"); + Long totalCount = (Long) q.uniqueResult(); + return totalCount == null ? 0 : totalCount.intValue(); + } + public int getTotalTextFlowTargets() { Query q = getSession() @@ -235,7 +262,8 @@ public Optional searchBestMatchTransMemory( .append(" tft.lastChanged DESC ") .append("LIMIT 1"); - SQLQuery sqlQuery = getSession().createSQLQuery(queryBuilder.toString()); + SQLQuery sqlQuery = + getSession().createSQLQuery(queryBuilder.toString()); sqlQuery.setParameter("textFlowId", textFlow.getId()); sqlQuery.setParameter("contentHash", textFlow.getContentHash()); sqlQuery.setParameter("resId", textFlow.getResId()); @@ -264,9 +292,10 @@ public HTextFlowTarget getOrCreateTarget(HTextFlow hTextFlow, hTextFlowTarget = new HTextFlowTarget(hTextFlow, hLocale); hTextFlowTarget.setVersionNum(0); // this will be incremented when // content is set (below) - // TODO getTargets just to make sure hTextFlowTarget is persisted in the end + // TODO getTargets just to make sure hTextFlowTarget is persisted in + // the end hTextFlow.getTargets().put(hLocale.getId(), hTextFlowTarget); -// getSession().persist(hTextFlowTarget); + // getSession().persist(hTextFlowTarget); } return hTextFlowTarget; } @@ -371,12 +400,11 @@ public long getTranslationCandidateCountWithDocIdAndLocale( HDocument document, HLocale targetLocale) { String queryString = - "select count(*) from HTextFlowTarget tft " - + - "where tft.textFlow.document.docId = :docId and tft.locale = :locale " - + - "and tft.textFlow.obsolete = false and tft.textFlow.document.obsolete = false " - + + "select count(*) from HTextFlowTarget tft " + + "where tft.textFlow.document.docId = :docId " + + "and tft.locale = :locale " + + "and tft.textFlow.obsolete = false " + + "and tft.textFlow.document.obsolete = false " + "and tft.textFlow.document.projectIteration <> :self"; Query query = getSession() @@ -403,19 +431,25 @@ public long getTranslationCandidateCountWithProjectAndLocale( HDocument document, HLocale targetLocale) { HProjectIteration projectIteration = document.getProjectIteration(); HProject project = projectIteration.getProject(); - String queryString = "select count(*) from HTextFlowTarget tft " + - "where tft.textFlow.document.projectIteration.project = :project and tft.locale = :locale " + - "and tft.textFlow.obsolete = false and tft.textFlow.document.obsolete = false " + - "and tft.textFlow.document.projectIteration.status <> :obsoleteStatus " + - "and tft.textFlow.document.projectIteration <> :self"; - Query query = getSession().createQuery(queryString) - .setParameter("project", project) - .setParameter("locale", targetLocale) - .setParameter("self", projectIteration) - .setParameter("obsoleteStatus", EntityStatus.OBSOLETE) - .setCacheable(true) - .setComment( - "TextFlowTargetDAO.getTranslationCandidateCountWithProjectAndLocale"); + String queryString = + "select count(*) from HTextFlowTarget tft " + + "where tft.textFlow.document.projectIteration.project = :project " + + "and tft.locale = :locale " + + "and tft.textFlow.obsolete = false " + + "and tft.textFlow.document.obsolete = false " + + "and tft.textFlow.document.projectIteration.status <> :obsoleteStatus " + + "and tft.textFlow.document.projectIteration <> :self"; + + Query query = + getSession() + .createQuery(queryString) + .setParameter("project", project) + .setParameter("locale", targetLocale) + .setParameter("self", projectIteration) + .setParameter("obsoleteStatus", EntityStatus.OBSOLETE) + .setCacheable(true) + .setComment( + "TextFlowTargetDAO.getTranslationCandidateCountWithProjectAndLocale"); return (Long) query.uniqueResult(); } } diff --git a/zanata-war/src/main/java/org/zanata/email/ActivationEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/ActivationEmailStrategy.java new file mode 100644 index 0000000000..d04f8b9616 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/ActivationEmailStrategy.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class ActivationEmailStrategy extends EmailStrategy { + private final String key; + + @Override + public String getSubject(Messages msgs) { + return msgs.get("jsf.email.activation.Subject"); + } + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/activation.vm"; + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext( + genericContext, toAddresses); + return context + .insert("activationKey", key) + .insert("toName", toAddresses[0].getPersonal()); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/Addresses.java b/zanata-war/src/main/java/org/zanata/email/Addresses.java new file mode 100644 index 0000000000..f343fb3f2b --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/Addresses.java @@ -0,0 +1,76 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import static com.google.common.base.Charsets.UTF_8; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import javax.mail.internet.InternetAddress; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import org.zanata.model.HPerson; + +/** + * Helper methods for working with JavaMail addresses. + * @author Sean Flanigan sflaniga@redhat.com + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Addresses { + private static final String UTF8 = UTF_8.name(); + + public static InternetAddress getAddress(String email, String name) { + try { + return new InternetAddress(email, name, UTF8); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + public static InternetAddress getAddress(HPerson person) { + return getAddress(person.getEmail(), person.getName()); + } + + public static InternetAddress[] getAddresses(List personList) { + List toAddresses = new ArrayList(); + for (HPerson coord : personList) { + toAddresses.add(getAddress(coord.getEmail(), coord.getName())); + } + return toAddresses.toArray(new InternetAddress[toAddresses.size()]); + } + + public static InternetAddress[] getAddresses(List emailList, String name) { + List toAddresses = new ArrayList(); + for (String email : emailList) { + toAddresses.add(getAddress(email, name)); + } + return toAddresses.toArray(new InternetAddress[toAddresses.size()]); + } + + public static InternetAddress[] getReplyTo(String email, String name) { + return new InternetAddress[] { getAddress(email, name) }; + } + +} diff --git a/zanata-war/src/main/java/org/zanata/email/ContactAdminEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/ContactAdminEmailStrategy.java new file mode 100644 index 0000000000..7fe8d154eb --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/ContactAdminEmailStrategy.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.google.common.base.Optional; +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +import static org.zanata.email.Addresses.getReplyTo; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class ContactAdminEmailStrategy extends EmailStrategy { + private final String fromLoginName; + private final String fromName; + private final String replyEmail; + private final String userSubject; + private final String htmlMessage; + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/email_admin.vm"; + } + + @Override + public Optional getReplyToAddress() { + return Optional.of(getReplyTo(replyEmail, fromName)); + } + + @Override + public String getSubject(Messages msgs) { + return msgs.format("jsf.email.admin.SubjectPrefix", + fromLoginName) + " " + userSubject; + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext( + genericContext, toAddresses); + String safeHTML = EmailUtil.SANITIZER.sanitize(htmlMessage); + return context + .insert("fromLoginName", fromLoginName) + .insert("fromName", fromName) + .insert("replyEmail", replyEmail) + .insert("htmlMessage", safeHTML); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/ContactLanguageCoordinatorEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/ContactLanguageCoordinatorEmailStrategy.java new file mode 100644 index 0000000000..e930e4c675 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/ContactLanguageCoordinatorEmailStrategy.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.google.common.base.Optional; +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +import static org.zanata.email.Addresses.getReplyTo; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class ContactLanguageCoordinatorEmailStrategy + extends EmailStrategy { + private final String fromLoginName; + private final String fromName; + private final String replyEmail; + private final String userSubject; + private final String localeId; + private final String localeNativeName; + private final String htmlMessage; + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/email_coordinator.vm"; + } + + @Override + public Optional getReplyToAddress() { + return Optional.of(getReplyTo(replyEmail, fromName)); + } + + @Override + public String getSubject(Messages msgs) { + return msgs.format("jsf.email.coordinator.SubjectPrefix", + localeId, fromLoginName) + " " + userSubject; + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext(genericContext, + toAddresses); + String safeHTML = EmailUtil.SANITIZER.sanitize(htmlMessage); + return context + .insert("fromLoginName", fromLoginName) + .insert("fromName", fromName) + .insert("replyEmail", replyEmail) + .insert("localeId", localeId) + .insert("localeNativeName", localeNativeName) + .insert("htmlMessage", safeHTML); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/EmailBuilder.java b/zanata-war/src/main/java/org/zanata/email/EmailBuilder.java new file mode 100644 index 0000000000..a02df72eab --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/EmailBuilder.java @@ -0,0 +1,211 @@ +package org.zanata.email; + +import static com.google.common.base.Charsets.UTF_8; +import static javax.mail.Message.RecipientType.TO; + +import java.io.StringWriter; +import java.net.ConnectException; + +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + +import com.google.common.base.Throwables; +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.AllArgsConstructor; + +import lombok.extern.slf4j.Slf4j; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.In; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; +import org.jboss.seam.mail.MailSession; +import org.zanata.ApplicationConfiguration; +import org.zanata.i18n.Messages; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; + +import static com.googlecode.totallylazy.collections.PersistentMap.constructors.map; +import static org.jboss.seam.ScopeType.EVENT; +import static org.jboss.seam.ScopeType.STATELESS; + +/** + * Uses an instance of EmailBuilderStrategy to build an email from a Velocity + * template and send it via the default JavaMail Transport. + */ +@AllArgsConstructor +@AutoCreate +@Name("emailBuilder") +@Scope(STATELESS) +@Slf4j +public class EmailBuilder { + // Use this if you want emails logged on stderr + // Warning: The full message may contain sensitive information + private static final boolean LOG_FULL_MESSAGES = false; + private static final VelocityEngine velocityEngine = makeVelocityEngine(); + + public EmailBuilder() { + this.mailSession = MailSession.instance(); + } + + // it seems to be impossible to inject this in Seam 2: + private final Session mailSession; + @In + private Context emailContext; + @In + private Messages msgs; + + private static VelocityEngine makeVelocityEngine() { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + ve.setProperty("classpath.resource.loader.class", + ClasspathResourceLoader.class.getName()); + // this allows unit tests to detect missing context vars: + ve.setProperty("runtime.references.strict", true); + ve.init(); + return ve; + } + + /** + * Build message using 'strategy' and send it via Transport to 'toAddress'. + * @param strategy + * @throws javax.mail.MessagingException + */ + public void sendMessage(EmailStrategy strategy, + String receivedReason, InternetAddress toAddress) { + sendMessage(strategy, receivedReason, new InternetAddress[] { + toAddress }); + } + + /** + * Build message using 'strategy' and send it via Transport to 'toAddresses'. + * @param strategy + * @throws javax.mail.MessagingException + */ + public void sendMessage(EmailStrategy strategy, + String receivedReason, InternetAddress[] toAddresses) { + try { + MimeMessage email = new MimeMessage(mailSession); + buildMessage(email, strategy, toAddresses, receivedReason); + logMessage(email); + Transport.send(email); + } catch (MessagingException e) { + Throwable rootCause = Throwables.getRootCause(e); + if (rootCause.getClass().equals(ConnectException.class) && rootCause.getMessage().equals("Connection refused")) { + throw new RuntimeException("The system failed to connect to mail service. Please contact the administrator!"); + } + throw new RuntimeException(e); + } + } + + private void logMessage(MimeMessage msg) { + try { + // NB the body may contain more sensitive information + if (log.isInfoEnabled()) { + log.info( + "Sending message with Subject \"{}\" to Recipients {} From {} Reply-To {}", + msg.getSubject(), msg.getAllRecipients(), msg.getFrom(), + msg.getReplyTo()); + } + // The stderr log is perhaps less likely to be distributed widely + // than normal logging + if (LOG_FULL_MESSAGES) { + msg.writeTo(System.err); + } + } catch (Exception e) { + log.warn("Unable to log MimeMessage", e); + } + } + + /** + * Fills in the provided MimeMessage 'msg' using 'strategy' to select the + * desired body template and to provide context variable values. Does not + * actually send the email. + * @param msg + * @param strategy + * @return + * @throws javax.mail.MessagingException + */ + @VisibleForTesting + MimeMessage buildMessage(MimeMessage msg, EmailStrategy strategy, + InternetAddress[] toAddresses, String receivedReason) + throws MessagingException { + + Optional from = strategy.getFromAddress(); + msg.setFrom(from.or(Addresses.getAddress( + emailContext.getFromAddress(), emailContext.getFromName()))); + Optional replyTo = strategy.getReplyToAddress(); + if (replyTo.isPresent()) { + msg.setReplyTo(replyTo.get()); + } + msg.addRecipients(TO, toAddresses); + msg.setSubject(strategy.getSubject(msgs), UTF_8.name()); + // optional future extension +// strategy.setMailHeaders(msg, msgs); + + PersistentMap genericContext = map( + "msgs", msgs, + "receivedReason", receivedReason, + "serverPath", emailContext.getServerPath()); + + // the Map needs to be mutable for "foreach" to work + VelocityContext context = new VelocityContext( + strategy.makeContext(genericContext, toAddresses).toMutableMap()); + Template template = + velocityEngine.getTemplate(strategy.getTemplateResourceName()); + StringWriter writer = new StringWriter(); + template.merge(context, writer); + String body = writer.toString(); + + // Alternative parts should be added in increasing order of preference, + // ie the preferred format should be added last. + Multipart mp = new MimeMultipart("alternative"); + + MimeBodyPart textPart = new MimeBodyPart(); + String text = EmailUtil.htmlToText(body); + textPart.setText(text, "UTF-8"); + mp.addBodyPart(textPart); + + MimeBodyPart htmlPart = new MimeBodyPart(); + htmlPart.setContent(body, "text/html; charset=UTF-8"); + mp.addBodyPart(htmlPart); + + msg.setContent(mp); + return msg; + } + + /** + * A Seam component which can inject the required configuration and + * components needed to create EmailBuilder at runtime. + */ + @AutoCreate + @Name("emailContext") + @Scope(EVENT) + public static class Context { + @In + private ApplicationConfiguration applicationConfiguration; + @In + private Messages msgs; + String getServerPath() { + return applicationConfiguration.getServerPath(); + } + String getFromAddress() { + return applicationConfiguration.getFromEmailAddr(); + } + String getFromName() { + return msgs.get("jsf.Zanata"); + } + } + +} diff --git a/zanata-war/src/main/java/org/zanata/email/EmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/EmailStrategy.java new file mode 100644 index 0000000000..e8a6a1d90c --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/EmailStrategy.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import javax.mail.internet.InternetAddress; + +import com.google.common.base.Optional; +import com.googlecode.totallylazy.collections.PersistentMap; +import org.zanata.i18n.Messages; + +/** + * Strategy class for EmailBuilder to customise the content and recipients + * of an email. + * @author Sean Flanigan sflaniga@redhat.com + */ +public abstract class EmailStrategy { + + /** + * For absent, use the default From address configured by the server + * @return + */ + public Optional getFromAddress() { + return Optional.absent(); + } + + public Optional getReplyToAddress(){ + return Optional.absent(); + } + + public abstract String getSubject(Messages msgs); + + /** + * The classpath resource name of the Velocity template which + * will provide the complete email. + * @return the resource name + */ + public String getTemplateResourceName() { + return "org/zanata/email/templates/template_email.vm"; + } + + /** + * The classpath resource name of the Velocity template which + * will provide the body of the email. + * @return the resource name + */ + public abstract String getBodyResourceName(); + + /** + * A map of variable name to value for the context variables needed + * by this strategy's template. + * @return the context variables + * @param genericContext + * @param toAddresses + */ + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + return genericContext.insert("body", getBodyResourceName()); + } + +} diff --git a/zanata-war/src/main/java/org/zanata/email/EmailUtil.java b/zanata-war/src/main/java/org/zanata/email/EmailUtil.java new file mode 100644 index 0000000000..5fc98c8ebe --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/EmailUtil.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import net.htmlparser.jericho.Renderer; +import net.htmlparser.jericho.Segment; +import net.htmlparser.jericho.Source; +import org.owasp.html.PolicyFactory; + +import static org.owasp.html.Sanitizers.BLOCKS; +import static org.owasp.html.Sanitizers.FORMATTING; +import static org.owasp.html.Sanitizers.IMAGES; +import static org.owasp.html.Sanitizers.LINKS; + +/** + * @author Sean Flanigan sflaniga@redhat.com + */ +public class EmailUtil { + // Don't allow CSS styles, scripts, etc + public static final PolicyFactory SANITIZER = + BLOCKS.and(FORMATTING).and(IMAGES).and(LINKS); + + /** + * Converts HTML to plain text. 'br' tags become newlines, and URLs in + * links are inserted after the text of the link. + * @param html + * @return + */ + public static String htmlToText(String html) { + Source htmlSource = new Source(html); + Segment htmlSeg = new Segment(htmlSource, 0, htmlSource.length()); + Renderer htmlRend = new Renderer(htmlSeg); + return htmlRend.toString(); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/EmailValidationEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/EmailValidationEmailStrategy.java new file mode 100644 index 0000000000..a525be145f --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/EmailValidationEmailStrategy.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class EmailValidationEmailStrategy extends + EmailStrategy { + private final String key; + + @Override + public String getSubject(Messages msgs) { + return msgs.get("jsf.email.accountchange.Subject"); + } + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/email_validation.vm"; + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext(genericContext, + toAddresses); + return context + .insert("activationKey", key) + .insert("newEmail", toAddresses[0].getAddress()) + .insert("toName", toAddresses[0].getPersonal()); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/PasswordResetEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/PasswordResetEmailStrategy.java new file mode 100644 index 0000000000..14abbc30b2 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/PasswordResetEmailStrategy.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class PasswordResetEmailStrategy extends + EmailStrategy { + private final String key; + + @Override + public String getSubject(Messages msgs) { + return msgs.get("jsf.email.passwordreset.Subject"); + } + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/password_reset.vm"; + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext(genericContext, + toAddresses); + return context + .insert("activationKey", key) + .insert("toName", toAddresses[0].getPersonal()); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/RequestRoleLanguageEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/RequestRoleLanguageEmailStrategy.java new file mode 100644 index 0000000000..1bf6416caf --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/RequestRoleLanguageEmailStrategy.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.google.common.base.Optional; +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +import static org.zanata.email.Addresses.getReplyTo; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class RequestRoleLanguageEmailStrategy + extends EmailStrategy { + private final String fromLoginName; + private final String fromName; + private final String replyEmail; + private final String localeId; + private final String localeNativeName; + private final String htmlMessage; + private final boolean requestAsTranslator; + private final boolean requestAsReviewer; + private final boolean requestAsCoordinator; + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/email_request_role_language.vm"; + } + + @Override + public Optional getReplyToAddress() { + return Optional.of(getReplyTo(replyEmail, fromName)); + } + + @Override + public String getSubject(Messages msgs) { + return msgs.format("jsf.email.rolerequest.Subject", + fromLoginName, localeId); + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext( + genericContext, toAddresses); + String safeHTML = EmailUtil.SANITIZER.sanitize(htmlMessage); + return context + .insert("fromLoginName", fromLoginName) + .insert("fromName", fromName) + .insert("replyEmail", replyEmail) + .insert("localeId", localeId) + .insert("localeNativeName", localeNativeName) + .insert("htmlMessage", safeHTML) + .insert("requestAsTranslator", requestAsTranslator) + .insert("requestAsReviewer", requestAsReviewer) + .insert("requestAsCoordinator", requestAsCoordinator); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/RequestToJoinLanguageEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/RequestToJoinLanguageEmailStrategy.java new file mode 100644 index 0000000000..5a1a98b941 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/RequestToJoinLanguageEmailStrategy.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.google.common.base.Optional; +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +import static org.zanata.email.Addresses.getReplyTo; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class RequestToJoinLanguageEmailStrategy + extends EmailStrategy { + private final String fromLoginName; + private final String fromName; + private final String replyEmail; + private final String localeId; + private final String localeNativeName; + private final String htmlMessage; + private final boolean requestAsTranslator; + private final boolean requestAsReviewer; + private final boolean requestAsCoordinator; + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/email_request_to_join_language.vm"; + } + + @Override + public Optional getReplyToAddress() { + return Optional.of(getReplyTo(replyEmail, fromName)); + } + + @Override + public String getSubject(Messages msgs) { + return msgs.format("jsf.email.joinrequest.Subject", + fromLoginName, localeId); + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext( + genericContext, toAddresses); + String safeHTML = EmailUtil.SANITIZER.sanitize(htmlMessage); + return context + .insert("fromLoginName", fromLoginName) + .insert("fromName", fromName) + .insert("replyEmail", replyEmail) + .insert("localeId", localeId) + .insert("localeNativeName", localeNativeName) + .insert("htmlMessage", safeHTML) + .insert("requestAsTranslator", requestAsTranslator) + .insert("requestAsReviewer", requestAsReviewer) + .insert("requestAsCoordinator", requestAsCoordinator); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/RequestToJoinVersionGroupEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/RequestToJoinVersionGroupEmailStrategy.java new file mode 100644 index 0000000000..b615fffc02 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/RequestToJoinVersionGroupEmailStrategy.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.google.common.base.Optional; +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; +import org.zanata.webtrans.shared.model.ProjectIterationId; + +import javax.mail.internet.InternetAddress; +import java.util.Collection; + +import static org.zanata.email.Addresses.getReplyTo; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class RequestToJoinVersionGroupEmailStrategy + extends EmailStrategy { + private final String fromLoginName; + private final String fromName; + private final String replyEmail; + private final String groupName; + private final String groupSlug; + private final Collection projectIterationIds; + private final String htmlMessage; + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/email_request_to_join_group.vm"; + } + + @Override + public Optional getReplyToAddress() { + return Optional.of(getReplyTo(replyEmail, fromName)); + } + + @Override + public String getSubject(Messages msgs) { + return msgs.format("jsf.email.JoinGroupRequest.Subject", groupName); + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext( + genericContext, toAddresses); + String safeHTML = EmailUtil.SANITIZER.sanitize(htmlMessage); + return context + .insert("fromLoginName", fromLoginName) + .insert("fromName", fromName) + .insert("replyEmail", replyEmail) + .insert("groupName", groupName) + .insert("versionGroupSlug", groupSlug) + .insert("projectIterationIds", projectIterationIds) + .insert("htmlMessage", safeHTML); + } +} diff --git a/zanata-war/src/main/java/org/zanata/email/UsernameChangedEmailStrategy.java b/zanata-war/src/main/java/org/zanata/email/UsernameChangedEmailStrategy.java new file mode 100644 index 0000000000..54edc4a23a --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/email/UsernameChangedEmailStrategy.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.email; + +import com.googlecode.totallylazy.collections.PersistentMap; +import lombok.RequiredArgsConstructor; +import org.zanata.i18n.Messages; + +import javax.mail.internet.InternetAddress; + +/** +* @author Sean Flanigan sflaniga@redhat.com +*/ +@RequiredArgsConstructor +public class UsernameChangedEmailStrategy extends + EmailStrategy { + private final String newUserName; + private final boolean shouldResetPassword; + + @Override + public String getSubject(Messages msgs) { + return msgs.get("jsf.email.usernamechange.Subject"); + } + + @Override + public String getBodyResourceName() { + return "org/zanata/email/templates/username_changed.vm"; + } + + @Override + public PersistentMap makeContext( + PersistentMap genericContext, + InternetAddress[] toAddresses) { + PersistentMap context = super.makeContext(genericContext, + toAddresses); + return context + .insert("toName", toAddresses[0].getPersonal()) + .insert("newUsername", newUserName) + .insert("shouldResetPassword", shouldResetPassword); + } +} diff --git a/zanata-war/src/main/java/org/zanata/file/DocumentUploadUtil.java b/zanata-war/src/main/java/org/zanata/file/DocumentUploadUtil.java index 0bdb97f7ed..6f7f17de32 100644 --- a/zanata-war/src/main/java/org/zanata/file/DocumentUploadUtil.java +++ b/zanata-war/src/main/java/org/zanata/file/DocumentUploadUtil.java @@ -90,6 +90,13 @@ public void failIfUploadNotValid(GlobalDocumentId id, failIfVersionCannotAcceptUpload(id); } + public void failIfHashNotPresent(DocumentFileUploadForm uploadForm) { + if (isNullOrEmpty(uploadForm.getHash())) { + throw new ChunkUploadException(Status.PRECONDITION_FAILED, + "Required form parameter 'hash' was not found."); + } + } + private void failIfNotLoggedIn() throws ChunkUploadException { if (!identity.isLoggedIn()) { throw new ChunkUploadException( @@ -121,11 +128,6 @@ private static void failIfRequiredParametersNullOrEmpty( throw new ChunkUploadException(Status.PRECONDITION_FAILED, "Required form parameter 'type' was not found."); } - - if (isNullOrEmpty(uploadForm.getHash())) { - throw new ChunkUploadException(Status.PRECONDITION_FAILED, - "Required form parameter 'hash' was not found."); - } } private void failIfUploadPartIsOrphaned(GlobalDocumentId id, @@ -239,7 +241,7 @@ protected static boolean isSinglePart(DocumentFileUploadForm uploadForm) { } public File combineToTempFileAndDeleteUploadRecord(HDocumentUpload upload, - InputStream finalPart) { + DocumentFileUploadForm finalPart) { File tempFile; try { tempFile = combineToTempFile(upload, finalPart); @@ -261,13 +263,13 @@ public File combineToTempFileAndDeleteUploadRecord(HDocumentUpload upload, } private File - combineToTempFile(HDocumentUpload upload, InputStream finalPart) + combineToTempFile(HDocumentUpload upload, DocumentFileUploadForm finalPart) throws SQLException { Vector partStreams = new Vector(); for (HDocumentUploadPart part : upload.getParts()) { partStreams.add(part.getContent().getBinaryStream()); } - partStreams.add(finalPart); + partStreams.add(finalPart.getFileStream()); MessageDigest md; try { @@ -281,11 +283,8 @@ public File combineToTempFileAndDeleteUploadRecord(HDocumentUpload upload, combinedParts = new DigestInputStream(combinedParts, md); File tempFile = translationFileServiceImpl.persistToTempFile(combinedParts); - String md5hash = new String(Hex.encodeHex(md.digest())); - if (!md5hash.equals(upload.getContentHash())) { - throw new HashMismatchException("MD5 hashes do not match.\n", - upload.getContentHash(), md5hash); - } + + checkAndUpdateHash(finalPart, md, upload.getContentHash()); return tempFile; } @@ -313,13 +312,8 @@ protected File persistTempFileFromUpload(DocumentFileUploadForm uploadForm) { new DigestInputStream(uploadForm.getFileStream(), md); tempFile = translationFileServiceImpl.persistToTempFile(fileContents); - String md5hash = new String(Hex.encodeHex(md.digest())); - if (!md5hash.equals(uploadForm.getHash())) { - throw new ChunkUploadException(Status.CONFLICT, "MD5 hash \"" - + uploadForm.getHash() - + "\" sent with request does not match " - + "server-generated hash. Aborted upload operation."); - } + String providedHash = uploadForm.getHash(); + checkAndUpdateHash(uploadForm, md, providedHash); } catch (NoSuchAlgorithmException e) { throw new ChunkUploadException(Status.INTERNAL_SERVER_ERROR, "MD5 hash algorithm not available", e); @@ -327,4 +321,28 @@ protected File persistTempFileFromUpload(DocumentFileUploadForm uploadForm) { return tempFile; } + /** + * Makes sure any provided hash matches the calculated hash, and sets the + * calculated hash into the given upload form for use in subsequent steps. + * + * @param md an MD5 message digester that has had the contents of the file + * streamed through it. + * @param providedHash provided by client, may be null or empty + * @throws ChunkUploadException if a hash is provided and it does not match + * the hash of the file contents. + */ + private void checkAndUpdateHash(DocumentFileUploadForm uploadForm, + MessageDigest md, String providedHash) { + String md5hash = new String(Hex.encodeHex(md.digest())); + if (isNullOrEmpty(providedHash)) { + // Web upload with no hash provided, use generated hash for metadata + uploadForm.setHash(md5hash); + } else if (!md5hash.equals(providedHash)) { + throw new ChunkUploadException(Status.CONFLICT, "MD5 hash \"" + + providedHash + + "\" sent with request does not match " + + "server-generated hash. Aborted upload operation."); + } + } + } diff --git a/zanata-war/src/main/java/org/zanata/file/FilePersistService.java b/zanata-war/src/main/java/org/zanata/file/FilePersistService.java index 5a1074fd1d..c3b2cff205 100644 --- a/zanata-war/src/main/java/org/zanata/file/FilePersistService.java +++ b/zanata-war/src/main/java/org/zanata/file/FilePersistService.java @@ -32,6 +32,9 @@ public interface FilePersistService { public void persistRawDocumentContentFromFile(HRawDocument rawDocument, File rawFile); + void copyAndPersistRawDocument(HRawDocument fromDoc, + HRawDocument toDoc); + // TODO damason: parsing code only needs a file URI for this. Change to // return // uri when files are persisted to server. diff --git a/zanata-war/src/main/java/org/zanata/file/FileSystemPersistService.java b/zanata-war/src/main/java/org/zanata/file/FileSystemPersistService.java index d0a265af82..00ebba399b 100644 --- a/zanata-war/src/main/java/org/zanata/file/FileSystemPersistService.java +++ b/zanata-war/src/main/java/org/zanata/file/FileSystemPersistService.java @@ -79,6 +79,12 @@ public void persistRawDocumentContentFromFile(HRawDocument rawDocument, virusScanner.scan(newFile, globalId.toString()); } + @Override + public void copyAndPersistRawDocument(HRawDocument fromDoc, + HRawDocument toDoc) { + persistRawDocumentContentFromFile(toDoc, getFileForRawDocument(fromDoc)); + } + private File getFileForName(String fileName) { File docsPath = ensureDocsDirectory(); File newFile = new File(docsPath, fileName); diff --git a/zanata-war/src/main/java/org/zanata/file/SourceDocumentUpload.java b/zanata-war/src/main/java/org/zanata/file/SourceDocumentUpload.java index 63dc038517..9c131fbccc 100644 --- a/zanata-war/src/main/java/org/zanata/file/SourceDocumentUpload.java +++ b/zanata-war/src/main/java/org/zanata/file/SourceDocumentUpload.java @@ -89,11 +89,34 @@ public class SourceDocumentUpload { @In private DocumentService documentServiceImpl; + public Response tryUploadSourceFileWithoutHash(GlobalDocumentId id, + DocumentFileUploadForm uploadForm) { + try { + failIfSourceUploadNotValid(id, uploadForm); + } catch (ChunkUploadException e) { + return Response.status(e.getStatusCode()) + .entity(new ChunkUploadResponse(e.getMessage())).build(); + } + + return tryValidatedUploadSourceFile(id, uploadForm); + } + public Response tryUploadSourceFile(GlobalDocumentId id, DocumentFileUploadForm uploadForm) { try { failIfSourceUploadNotValid(id, uploadForm); + util.failIfHashNotPresent(uploadForm); + } catch (ChunkUploadException e) { + return Response.status(e.getStatusCode()) + .entity(new ChunkUploadResponse(e.getMessage())).build(); + } + return tryValidatedUploadSourceFile(id, uploadForm); + } + + public Response tryValidatedUploadSourceFile(GlobalDocumentId id, + DocumentFileUploadForm uploadForm) { + try { Optional tempFile; int totalChunks; @@ -121,10 +144,10 @@ public Response tryUploadSourceFile(GlobalDocumentId id, Optional.of(util .combineToTempFileAndDeleteUploadRecord( previousParts, - uploadForm.getFileStream())); + uploadForm)); } - if (uploadForm.getFileType().equals(".pot")) { + if (DocumentType.typeFor(uploadForm.getFileType()) == DocumentType.GETTEXT_PORTABLE_OBJECT_TEMPLATE) { InputStream potStream = getInputStream(tempFile, uploadForm); parsePotFile(potStream, id, uploadForm); } else { @@ -249,7 +272,7 @@ private void processAdapterFile(@Nonnull File tempFile, translationFileServiceImpl.parseUpdatedAdapterDocumentFile( tempFile.toURI(), id.getDocId(), uploadForm.getFileType(), params); - doc.setLang(new LocaleId("en-US")); + doc.setLang(LocaleId.EN_US); // TODO Copy Trans values document = documentServiceImpl.saveDocument(id.getProjectSlug(), @@ -292,12 +315,13 @@ private void persistRawDocument(HDocument document, File rawFile, private void parsePotFile(InputStream potStream, GlobalDocumentId id, DocumentFileUploadForm uploadForm) { - Resource doc; - doc = - translationFileServiceImpl.parseUpdatedPotFile(potStream, - id.getDocId(), uploadForm.getFileType(), + // real upload filename not available, but the service only cares about + // the suffix. + String uploadFileName = "." + uploadForm.getFileType(); + Resource doc = translationFileServiceImpl.parseUpdatedPotFile(potStream, + id.getDocId(), uploadFileName, useOfflinePo(id)); - doc.setLang(new LocaleId("en-US")); + doc.setLang(LocaleId.EN_US); // TODO Copy Trans values documentServiceImpl.saveDocument(id.getProjectSlug(), id.getVersionSlug(), doc, diff --git a/zanata-war/src/main/java/org/zanata/file/TranslationDocumentUpload.java b/zanata-war/src/main/java/org/zanata/file/TranslationDocumentUpload.java index cb0af8ce0e..d6845458d1 100644 --- a/zanata-war/src/main/java/org/zanata/file/TranslationDocumentUpload.java +++ b/zanata-war/src/main/java/org/zanata/file/TranslationDocumentUpload.java @@ -114,7 +114,7 @@ public class TranslationDocumentUpload { Optional.of(util .combineToTempFileAndDeleteUploadRecord( previousParts, - uploadForm.getFileStream())); + uploadForm)); } } @@ -168,6 +168,7 @@ private void failIfTranslationUploadNotValid(GlobalDocumentId id, String localeId, DocumentFileUploadForm uploadForm) throws ChunkUploadException { util.failIfUploadNotValid(id, uploadForm); + util.failIfHashNotPresent(uploadForm); failIfDocumentDoesNotExist(id); failIfFileTypeNotValid(uploadForm); failIfTranslationUploadNotAllowed(id, localeId); @@ -227,7 +228,7 @@ private HLocale findHLocale(String localeString) { } private boolean isTranslationUploadAllowed(GlobalDocumentId id, - HLocale localeId) { + HLocale locale) { HProjectIteration projectIteration = projectIterationDAO.getBySlug(id.getProjectSlug(), id.getVersionSlug()); @@ -237,7 +238,7 @@ private boolean isTranslationUploadAllowed(GlobalDocumentId id, && projectIteration.getProject().getStatus() == EntityStatus.ACTIVE && identity != null && identity.hasPermission("add-translation", - projectIteration.getProject(), localeId); + projectIteration.getProject(), locale); } private static Set newExtensions(boolean gettextExtensions) { diff --git a/zanata-war/src/main/java/org/zanata/file/UserFileUploadTracker.java b/zanata-war/src/main/java/org/zanata/file/UserFileUploadTracker.java new file mode 100644 index 0000000000..c063ad86c0 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/file/UserFileUploadTracker.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.file; + +import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; + +import java.util.HashSet; +import java.util.Set; + +/** + * Service to track which users are currently uploading files. + * + * This is intended to limit each user to a single upload operation at a time + * to prevent an individual user tying up too many server resources. + */ +@Name("userFileUploadTracker") +@Scope(ScopeType.APPLICATION) +@AutoCreate +public class UserFileUploadTracker { + + Set uploadingUsers = new HashSet(); + + /** + * Attempt to register a user as uploading a file. + * + * The attempt will succeed if the user is not already uploading a file, + * and will fail otherwise. + * + * The check and registration are performed in a single operation to reduce the + * chance of race conditions. + * + * @param userId for which to register an upload. + * @return true if this attempt to register the user as uploading is successful. + */ + public boolean tryToRegisterUserForFileUpload(Long userId) { + if (uploadingUsers.contains(userId)) { + return false; + } + uploadingUsers.add(userId); + return true; + } + + public boolean isUserUploading(Long userId) { + return uploadingUsers.contains(userId); + } + + /** + * Reverse a registration for uploading a file, as registered using + * {@link #tryToRegisterUserForFileUpload(Long)}. + * + * The given userId will not be registered for upload when this call completes. + * + * @param userId to de-register + */ + public void deRegisterUserForFileUpload(Long userId) { + uploadingUsers.remove(userId); + } + +} diff --git a/zanata-war/src/main/java/org/zanata/i18n/Messages.java b/zanata-war/src/main/java/org/zanata/i18n/Messages.java new file mode 100644 index 0000000000..9814b3fc01 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/i18n/Messages.java @@ -0,0 +1,192 @@ +/* + * Copyright 2010, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.i18n; + +import java.text.MessageFormat; +import java.util.AbstractMap; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Set; + +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; +import org.zanata.util.EmptyEnumeration; + +import javax.annotation.Nonnull; + +import static org.jboss.seam.ScopeType.EVENT; + +/** + * Utility component to help with programmatic access to the message resource + * bundle. + * + * Unlike the {@link org.jboss.seam.international.Messages} component, this + * component formats messages using positional arguments like {0} and + * {1}, not by interpolating EL expressions. + * + * @author Carlos Munoz camunoz@redhat.com + * @author Sean Flanigan sflaniga@redhat.com + */ +@AutoCreate +@Name("msgs") +@Scope(EVENT) +public class Messages extends AbstractMap { + + private static ResourceBundle getResourceBundle() { + // Generic ResourceBundle without built-in interpolation: + ResourceBundle resourceBundle = null; + try { + resourceBundle = ResourceBundle.getBundle( + "messages", org.jboss.seam.core.Locale.instance()); + } catch (MissingResourceException e) { + resourceBundle = new ResourceBundle() { + @Override + protected Object handleGetObject(@Nonnull String key) { + return key; + } + + @Override + @Nonnull + public Enumeration getKeys() { + return EmptyEnumeration.instance(); + } + }; + } + return resourceBundle; + } + + private final ResourceBundle resourceBundle; + + public Messages() { + this.resourceBundle = getResourceBundle(); + } + + // the default toString includes the entire list of properties, + // which makes a mess of the log file + @Override + public String toString() { + return getClass().getName(); + } + + /** + * Gets a resource string, without any message formatting. (So an + * apostrophe just represents an apostrophe (single quote).) + * @param key + * @return + */ + @Override + public String get(Object key) { + if (key instanceof String) { + String resourceKey = (String) key; + try { + String resource = resourceBundle.getString(resourceKey); + return (resource == null) ? resourceKey : resource; + } catch (MissingResourceException mre) { + return resourceKey; + } + } else { + return null; + } + } + + /** + * @deprecated use get(key) or format(key, args...) + * @param key + * @return + */ + @Deprecated + public String format(String key) { + return format(key, new Object[0]); + } + + /** + * Gets a resource string, and formats it using MessageFormat and the + * positional parameters. Due to the use of {@link java.util.MessageFormat} + * any literal apostrophes (single quotes) will need to be doubled, + * otherwise they will be interpreted as quoting format patterns. + * @param key + * @param args + * @return + * @see java.util.MessageFormat + */ + public String format(String key, Object... args) { + String template = get(key); + return MessageFormat.format(template, args); + } + + // JSF can't handle varargs, hence the need for these overloaded methods: + public String format(String key, Object arg1) { + return format(key, new Object[] {arg1}); + } + + public String format(String key, Object arg1, Object arg2) { + return format(key, new Object[] {arg1, arg2}); + } + + public String format(String key, Object arg1, Object arg2, Object arg3) { + return format(key, new Object[] {arg1, arg2, arg3}); + } + + public String format(String key, Object arg1, Object arg2, Object arg3, Object arg4) { + return format(key, new Object[] {arg1, arg2, arg3, arg4}); + } + + public String format(String key, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { + return format(key, new Object[] {arg1, arg2, arg3, arg4, arg5}); + } + + public String format(String key, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { + return format(key, new Object[] {arg1, arg2, arg3, arg4, arg5, arg6}); + } + + @Override + public Set> entrySet() { + Set> entrySet = + new HashSet>(); + + for (final String key : resourceBundle.keySet()) { + entrySet.add(new Map.Entry() { + + @Override + public String getKey() { + return key; + } + + @Override + public String getValue() { + return get(key); + } + + @Override + public String setValue(String val) { + throw new UnsupportedOperationException(); + } + }); + } + return entrySet; + } +} diff --git a/zanata-war/src/main/java/org/zanata/limits/RateLimitManager.java b/zanata-war/src/main/java/org/zanata/limits/RateLimitManager.java index 4fe55c558a..e6feae77a4 100644 --- a/zanata-war/src/main/java/org/zanata/limits/RateLimitManager.java +++ b/zanata-war/src/main/java/org/zanata/limits/RateLimitManager.java @@ -8,7 +8,6 @@ import com.google.common.annotations.VisibleForTesting; import lombok.AccessLevel; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Create; @@ -24,6 +23,7 @@ import com.google.common.collect.Lists; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.zanata.util.ServiceLocator; /** * @author Patrick Huang call() throws Exception { TranslationService translationServiceImpl = - (TranslationService) Component - .getInstance(TranslationServiceImpl.class); + ServiceLocator.instance().getInstance( + TranslationServiceImpl.class); // Translate List messages = diff --git a/zanata-war/src/main/java/org/zanata/rest/service/ProjectIterationService.java b/zanata-war/src/main/java/org/zanata/rest/service/ProjectIterationService.java index 0ddfdfa033..9ca97ded42 100644 --- a/zanata-war/src/main/java/org/zanata/rest/service/ProjectIterationService.java +++ b/zanata-war/src/main/java/org/zanata/rest/service/ProjectIterationService.java @@ -50,6 +50,7 @@ import org.zanata.model.HProject; import org.zanata.model.HProjectIteration; import org.zanata.rest.dto.ProjectIteration; +import org.zanata.service.ConfigurationService; import com.google.common.base.Objects; @@ -95,6 +96,9 @@ public class ProjectIterationService implements ProjectIterationResource { @In Identity identity; + @In + private ConfigurationService configurationServiceImpl; + @SuppressWarnings("null") @Nonnull public String getProjectSlug() { @@ -134,6 +138,9 @@ public Response get() { HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(getProjectSlug(), getIterationSlug()); + if (hProjectIteration == null) { + return Response.status(Status.NOT_FOUND).build(); + } ProjectIteration it = new ProjectIteration(); transfer(hProjectIteration, it); @@ -310,4 +317,15 @@ public static void transfer(HProjectIteration from, ProjectIteration to) { } } + @Override + public Response sampleConfiguration() { + HProjectIteration iteration = + projectIterationDAO.getBySlug(projectSlug, iterationSlug); + if (iteration == null) { + return Response.status(Status.NOT_FOUND).build(); + } + String generalConfig = configurationServiceImpl + .getGeneralConfig(projectSlug, iterationSlug); + return Response.ok().entity(generalConfig).build(); + } } diff --git a/zanata-war/src/main/java/org/zanata/rest/service/ProjectService.java b/zanata-war/src/main/java/org/zanata/rest/service/ProjectService.java index fa6a4e109a..5f72c7e4c1 100644 --- a/zanata-war/src/main/java/org/zanata/rest/service/ProjectService.java +++ b/zanata-war/src/main/java/org/zanata/rest/service/ProjectService.java @@ -169,9 +169,6 @@ else if (Objects.equal(hProject.getStatus(), READONLY)) { transfer(project, hProject); - hProject = projectDAO.makePersistent(hProject); - projectDAO.flush(); - if (identity != null && hProject.getMaintainers().isEmpty()) { HAccount hAccount = accountDAO.getByUsername(identity.getCredentials() @@ -179,9 +176,10 @@ else if (Objects.equal(hProject.getStatus(), READONLY)) { if (hAccount != null && hAccount.getPerson() != null) { hProject.getMaintainers().add(hAccount.getPerson()); } - projectDAO.flush(); } + projectDAO.makePersistent(hProject); + projectDAO.flush(); etag = eTagUtils.generateTagForProject(projectSlug); return response.tag(etag).build(); diff --git a/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java b/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java index 16fc6908bf..a1909ce2b9 100644 --- a/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java +++ b/zanata-war/src/main/java/org/zanata/rest/service/ResourceUtils.java @@ -34,7 +34,6 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.fedorahosted.tennera.jgettext.HeaderFields; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; @@ -71,6 +70,7 @@ import org.zanata.rest.dto.resource.TextFlow; import org.zanata.rest.dto.resource.TextFlowTarget; import org.zanata.rest.dto.resource.TranslationsResource; +import org.zanata.util.ServiceLocator; import org.zanata.util.StringUtil; import com.google.common.base.Optional; @@ -919,8 +919,9 @@ private String getSystemVersion() { try { return ZANATA_GENERATOR_PREFIX + " " - + ((ApplicationConfiguration) Component.getInstance( - ApplicationConfiguration.class)).getVersion(); + + (ServiceLocator.instance() + .getInstance(ApplicationConfiguration.class)) + .getVersion(); } catch (Exception e) { return ZANATA_GENERATOR_PREFIX + " UNKNOWN"; } diff --git a/zanata-war/src/main/java/org/zanata/seam/FixedSafeActions.java b/zanata-war/src/main/java/org/zanata/seam/FixedSafeActions.java index 4d46648881..1e5a612a8a 100644 --- a/zanata-war/src/main/java/org/zanata/seam/FixedSafeActions.java +++ b/zanata-war/src/main/java/org/zanata/seam/FixedSafeActions.java @@ -12,13 +12,13 @@ import javax.faces.context.FacesContext; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.contexts.Contexts; +import org.zanata.util.ServiceLocator; /** * Maintains a set of "safe" actions that may be performed by <s:link/>, @@ -99,8 +99,7 @@ public static FixedSafeActions instance() { if (!Contexts.isApplicationContextActive()) { throw new IllegalStateException("No active application context"); } - return (FixedSafeActions) Component.getInstance(FixedSafeActions.class, - ScopeType.APPLICATION); + return ServiceLocator.instance().getInstance(FixedSafeActions.class); } } diff --git a/zanata-war/src/main/java/org/zanata/seam/interceptor/CachedMethodResultInterceptor.java b/zanata-war/src/main/java/org/zanata/seam/interceptor/CachedMethodResultInterceptor.java deleted file mode 100644 index 5802cc1797..0000000000 --- a/zanata-war/src/main/java/org/zanata/seam/interceptor/CachedMethodResultInterceptor.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2010, Red Hat, Inc. and individual contributors as indicated by the - * @author tags. See the copyright.txt file in the distribution for a full - * listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this software; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF - * site: http://www.fsf.org. - */ -package org.zanata.seam.interceptor; - -import java.lang.reflect.Method; - -import org.apache.commons.collections.keyvalue.MultiKey; -import org.apache.commons.collections.map.MultiKeyMap; -import org.jboss.seam.annotations.intercept.AroundInvoke; -import org.jboss.seam.annotations.intercept.Interceptor; -import org.jboss.seam.contexts.Context; -import org.jboss.seam.intercept.InvocationContext; -import org.jboss.seam.intercept.JavaBeanInterceptor; -import org.jboss.seam.intercept.OptimizedInterceptor; -import org.zanata.annotation.CachedMethodResult; - -/** - * Interceptor class that caches method return values in a given context. - * - * @author camunoz@redhat.com - */ -@Interceptor(stateless = true, around = JavaBeanInterceptor.class) -public class CachedMethodResultInterceptor implements OptimizedInterceptor { - private static final String REG_CTX_KEY = "__CACHED_METHOD_RESULT_REG__"; - - @Override - @AroundInvoke - public Object aroundInvoke(InvocationContext ic) throws Exception { - Method m = ic.getMethod(); - CachedMethodResult cmr = m.getAnnotation(CachedMethodResult.class); - if (cmr != null) { - // the method result is cached => get it from the cache (or cache it - // if - // absent) - Context c = cmr.value().getContext(); - - // Create / Get an existing cached result registry - MultiKeyMap cachedResultReg = (MultiKeyMap) c.get(REG_CTX_KEY); - if (cachedResultReg == null) { - cachedResultReg = new MultiKeyMap(); - c.set(REG_CTX_KEY, cachedResultReg); - } - - Object[] keys = new Object[2 + ic.getParameters().length]; - int i = 0; - // Key by class name: - keys[i++] = ic.getTarget().getClass().getName(); - // Key by method name: - keys[i++] = m.getName(); - // Key by each parameter called: - for (Object param : ic.getParameters()) { - keys[i++] = param; - } - - MultiKey key = new MultiKey(keys); - - // Note: the key can be whatever unique value composed by the - // Interceptor and Method. The above key could be improved - Object result = null; - if (cachedResultReg.containsKey(key)) { - result = cachedResultReg.get(key); - } else { - // result not yet in cache => cache it - result = ic.proceed(); - cachedResultReg.put(key, result); - } - return result; - } else { - // the method is not cached => delegate call to the - // InvocationContext - return ic.proceed(); - } - } - - @Override - public boolean isInterceptorEnabled() { - return true; - } -} diff --git a/zanata-war/src/main/java/org/zanata/seam/interceptor/MonitoringWrapper.java b/zanata-war/src/main/java/org/zanata/seam/interceptor/MonitoringWrapper.java index bf22b54283..089300944b 100644 --- a/zanata-war/src/main/java/org/zanata/seam/interceptor/MonitoringWrapper.java +++ b/zanata-war/src/main/java/org/zanata/seam/interceptor/MonitoringWrapper.java @@ -28,12 +28,11 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; import org.jboss.seam.servlet.ContextualHttpServletRequest; import org.zanata.security.ZanataIdentity; import net.bull.javamelody.MonitoringFilter; +import org.zanata.util.ServiceLocator; public class MonitoringWrapper extends MonitoringFilter { @@ -49,8 +48,8 @@ public void doFilter(final ServletRequest request, @Override public void process() throws Exception { ZanataIdentity identity = - (ZanataIdentity) Component.getInstance( - ZanataIdentity.class, ScopeType.SESSION); + ServiceLocator.instance().getInstance( + ZanataIdentity.class); if (identity == null || !identity.isLoggedIn()) { String signInUrl = httpRequest.getContextPath() diff --git a/zanata-war/src/main/java/org/zanata/seam/mail/ZanataMailSession.java b/zanata-war/src/main/java/org/zanata/seam/mail/ZanataMailSession.java index 30b107f7b0..fa5c76d30c 100644 --- a/zanata-war/src/main/java/org/zanata/seam/mail/ZanataMailSession.java +++ b/zanata-war/src/main/java/org/zanata/seam/mail/ZanataMailSession.java @@ -20,14 +20,18 @@ */ package org.zanata.seam.mail; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; +import org.jboss.seam.annotations.Unwrap; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.mail.MailSession; import org.zanata.ApplicationConfiguration; +import org.zanata.util.ServiceLocator; + +import javax.mail.Session; +import javax.naming.NamingException; /** * Overrides Seam's default MailSession component to dynamically define @@ -51,10 +55,16 @@ public ZanataMailSession(String transport) { setup(); } + @Override + @Unwrap + public Session getSession() throws NamingException { + return super.getSession(); + } + protected void setup() { ApplicationConfiguration appConfig = - (ApplicationConfiguration) Component - .getInstance(ApplicationConfiguration.class); + ServiceLocator.instance().getInstance( + ApplicationConfiguration.class); // Override default properties setHost(appConfig.getEmailServerHost()); diff --git a/zanata-war/src/main/java/org/zanata/seam/scope/ConversationScopeMessages.java b/zanata-war/src/main/java/org/zanata/seam/scope/ConversationScopeMessages.java index c0d5ec69a2..44d5bb089c 100644 --- a/zanata-war/src/main/java/org/zanata/seam/scope/ConversationScopeMessages.java +++ b/zanata-war/src/main/java/org/zanata/seam/scope/ConversationScopeMessages.java @@ -26,13 +26,13 @@ import java.util.List; import javax.faces.application.FacesMessage; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Begin; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import com.google.common.collect.Lists; +import org.zanata.util.ServiceLocator; /** * @author Alex Eng aeng@redhat.com @@ -55,12 +55,10 @@ public void setMessages(List messages) { this.messages = messages; } - public List getMessages() { - return messages; - } - - public void clearMessages() { + public List getAndClearMessages() { + List tempMsgs = Lists.newArrayList(messages); messages.clear(); + return tempMsgs; } public boolean hasMessages() { @@ -68,7 +66,7 @@ public boolean hasMessages() { } public static ConversationScopeMessages instance() { - return (ConversationScopeMessages) Component - .getInstance(ConversationScopeMessages.class); + return ServiceLocator.instance().getInstance( + ConversationScopeMessages.class); } } diff --git a/zanata-war/src/main/java/org/zanata/search/AbstractIndexingStrategy.java b/zanata-war/src/main/java/org/zanata/search/AbstractIndexingStrategy.java index f61146bfaa..edad444c38 100644 --- a/zanata-war/src/main/java/org/zanata/search/AbstractIndexingStrategy.java +++ b/zanata-war/src/main/java/org/zanata/search/AbstractIndexingStrategy.java @@ -17,23 +17,21 @@ public abstract class AbstractIndexingStrategy { private int sessionClearBatchSize = 1000; private ScrollableResults scrollableResults; private final Class entityType; - private final FullTextSession session; /** * @param entityType * The type of entity to be returned by the Scrollable results */ - public AbstractIndexingStrategy(Class entityType, FullTextSession session) { + public AbstractIndexingStrategy(Class entityType) { this.entityType = entityType; - this.session = session; } /** * Performs the indexing. */ - public void invoke(AsyncTaskHandle handle) { + public void invoke(AsyncTaskHandle handle, FullTextSession session) { int rowNum = 0; - scrollableResults = queryResults(rowNum); + scrollableResults = queryResults(rowNum, session); try { while (scrollableResults.next()) { if (handle != null && handle.isCancelled()) { @@ -52,7 +50,7 @@ public void invoke(AsyncTaskHandle handle) { session.flushToIndexes(); // apply changes to indexes session.clear(); // clear since the queue is processed } - onEntityIndexed(rowNum); + onEntityIndexed(rowNum, session); } } finally { if (scrollableResults != null) { @@ -67,7 +65,7 @@ public void invoke(AsyncTaskHandle handle) { * @param n * The entity number that was indexed. */ - protected abstract void onEntityIndexed(int n); + protected abstract void onEntityIndexed(int n, FullTextSession session); /** * Returns the Scrollable results for instances of clazz @@ -75,7 +73,7 @@ public void invoke(AsyncTaskHandle handle) { * @param offset * @return */ - protected abstract ScrollableResults queryResults(int offset); + protected abstract ScrollableResults queryResults(int offset, FullTextSession session); Class getEntityType() { return entityType; @@ -89,8 +87,4 @@ void setScrollableResults(ScrollableResults scrollableResults) { this.scrollableResults = scrollableResults; } - FullTextSession getSession() { - return session; - } - } diff --git a/zanata-war/src/main/java/org/zanata/search/ClassIndexer.java b/zanata-war/src/main/java/org/zanata/search/ClassIndexer.java index 6cbff14bbf..ca1abb5dfa 100644 --- a/zanata-war/src/main/java/org/zanata/search/ClassIndexer.java +++ b/zanata-war/src/main/java/org/zanata/search/ClassIndexer.java @@ -38,13 +38,11 @@ public class ClassIndexer { private final AbstractIndexingStrategy indexingStrategy; - private FullTextSession session; private AsyncTaskHandle handle; private Class entityType; - public ClassIndexer(FullTextSession session, AsyncTaskHandle handle, + public ClassIndexer(AsyncTaskHandle handle, Class entityType, AbstractIndexingStrategy indexingStrategy) { - this.session = session; this.handle = handle; this.entityType = entityType; this.indexingStrategy = indexingStrategy; @@ -54,18 +52,18 @@ public AbstractIndexingStrategy getIndexingStrategy() { return indexingStrategy; } - public int getEntityCount() { + public int getEntityCount(FullTextSession session) { Long result = (Long) session.createCriteria(entityType) .setProjection(Projections.rowCount()).list().get(0); return result.intValue(); } - public void index() throws Exception { + public void index(FullTextSession session) throws Exception { log.info("Setting manual-flush and ignore-cache for {}", entityType); session.setFlushMode(FlushMode.MANUAL); session.setCacheMode(CacheMode.IGNORE); - indexingStrategy.invoke(handle); + indexingStrategy.invoke(handle, session); session.flushToIndexes(); // apply changes to indexes session.clear(); // clear since the queue is processed } diff --git a/zanata-war/src/main/java/org/zanata/search/HTextFlowTargetIndexingStrategy.java b/zanata-war/src/main/java/org/zanata/search/HTextFlowTargetIndexingStrategy.java index bd476d99bd..e51efb9cda 100644 --- a/zanata-war/src/main/java/org/zanata/search/HTextFlowTargetIndexingStrategy.java +++ b/zanata-war/src/main/java/org/zanata/search/HTextFlowTargetIndexingStrategy.java @@ -36,21 +36,20 @@ */ public class HTextFlowTargetIndexingStrategy extends AbstractIndexingStrategy { - public HTextFlowTargetIndexingStrategy(FullTextSession session) { - super(HTextFlowTarget.class, session); + public HTextFlowTargetIndexingStrategy() { + super(HTextFlowTarget.class); } @Override - protected void onEntityIndexed(int n) { + protected void onEntityIndexed(int n, FullTextSession session) { // Nothing to do } @Override - protected ScrollableResults queryResults(int ignoredOffset) { + protected ScrollableResults queryResults(int ignoredOffset, FullTextSession session) { // TODO move this query into something like HTextFlowTargetStreamingDAO Query query = - getSession() - .createQuery( + session.createQuery( "from HTextFlowTarget tft " + "join fetch tft.locale " + "join fetch tft.textFlow " diff --git a/zanata-war/src/main/java/org/zanata/search/SimpleClassIndexingStrategy.java b/zanata-war/src/main/java/org/zanata/search/SimpleClassIndexingStrategy.java index 803022a369..ebc4d093df 100644 --- a/zanata-war/src/main/java/org/zanata/search/SimpleClassIndexingStrategy.java +++ b/zanata-war/src/main/java/org/zanata/search/SimpleClassIndexingStrategy.java @@ -39,25 +39,24 @@ public class SimpleClassIndexingStrategy extends AbstractIndexingStrategy { public static final int MAX_QUERY_ROWS = 5000; - public SimpleClassIndexingStrategy(Class entityType, - FullTextSession session) { - super(entityType, session); + public SimpleClassIndexingStrategy(Class entityType) { + super(entityType); } @Override - protected void onEntityIndexed(int rowNum) { + protected void onEntityIndexed(int rowNum, FullTextSession session) { if (rowNum % MAX_QUERY_ROWS == 0) { log.info("restarting query for {} (rowNum={})", getEntityType(), rowNum); getScrollableResults().close(); - setScrollableResults(queryResults(rowNum)); + setScrollableResults(queryResults(rowNum, session)); } } @Override - protected ScrollableResults queryResults(int offset) { + protected ScrollableResults queryResults(int offset, FullTextSession session) { Query query = - getSession().createQuery("from " + getEntityType().getName()); + session.createQuery("from " + getEntityType().getName()); query.setFirstResult(offset); query.setMaxResults(MAX_QUERY_ROWS); return query.scroll(ScrollMode.FORWARD_ONLY); diff --git a/zanata-war/src/main/java/org/zanata/security/AuthenticationManager.java b/zanata-war/src/main/java/org/zanata/security/AuthenticationManager.java index 7daa18ee97..3d7cdaa30a 100644 --- a/zanata-war/src/main/java/org/zanata/security/AuthenticationManager.java +++ b/zanata-war/src/main/java/org/zanata/security/AuthenticationManager.java @@ -23,7 +23,6 @@ import java.util.List; import org.apache.commons.lang.StringUtils; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; @@ -39,6 +38,7 @@ import org.zanata.security.openid.OpenIdAuthCallback; import org.zanata.security.openid.OpenIdProviderType; import org.zanata.service.UserAccountService; +import org.zanata.util.ServiceLocator; /** * Centralizes all attempts to authenticate locally or externally. @@ -155,8 +155,7 @@ public String jaasLogin() { public void kerberosLogin() { if (applicationConfiguration.isKerberosAuth()) { SpNegoIdentity spNegoIdentity = - (SpNegoIdentity) Component.getInstance( - SpNegoIdentity.class, ScopeType.SESSION); + ServiceLocator.instance().getInstance(SpNegoIdentity.class); spNegoIdentity.authenticate(); if (!isNewUser() && !isAuthenticatedAccountWaitingForActivation() && isAccountEnabledAndActivated()) { @@ -380,7 +379,7 @@ private boolean isAccountEnabledAndActivated() { } else { String message = ""; if (isAccountWaitingForActivation(username)) { - message = "#{messages['org.jboss.seam.loginFailed']}"; + message = "#{msgs['org.jboss.seam.loginFailed']}"; } else { message = "User " diff --git a/zanata-war/src/main/java/org/zanata/security/FedoraOpenIdPhaseListener.java b/zanata-war/src/main/java/org/zanata/security/FedoraOpenIdPhaseListener.java index 3e1524d31c..8289e47154 100644 --- a/zanata-war/src/main/java/org/zanata/security/FedoraOpenIdPhaseListener.java +++ b/zanata-war/src/main/java/org/zanata/security/FedoraOpenIdPhaseListener.java @@ -29,10 +29,10 @@ import javax.faces.event.PhaseListener; import javax.servlet.http.HttpServletResponse; -import org.jboss.seam.Component; import org.jboss.seam.navigation.Pages; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.zanata.util.ServiceLocator; public class FedoraOpenIdPhaseListener implements PhaseListener { private static final Logger LOGGER = LoggerFactory @@ -48,7 +48,7 @@ public void beforePhase(PhaseEvent event) { } ZanataOpenId openid = - (ZanataOpenId) Component.getInstance(ZanataOpenId.class); + ServiceLocator.instance().getInstance(ZanataOpenId.class); if (openid.getId() == null) { try { sendXRDS(); @@ -74,7 +74,7 @@ private void sendXRDS() throws IOException { // XXX ENCODE THE URL! ZanataOpenId open = - (ZanataOpenId) Component.getInstance(ZanataOpenId.class); + ServiceLocator.instance().getInstance(ZanataOpenId.class); out.println("" + "http://specs.openid.net/auth/2.0/return_to" diff --git a/zanata-war/src/main/java/org/zanata/security/JBossSSOLoginModule.java b/zanata-war/src/main/java/org/zanata/security/JBossSSOLoginModule.java new file mode 100644 index 0000000000..67a02a7b0b --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/security/JBossSSOLoginModule.java @@ -0,0 +1,145 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.security; + +import java.io.IOException; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import lombok.extern.slf4j.Slf4j; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.map.ObjectMapper; +import org.jboss.seam.security.SimplePrincipal; +import org.zanata.util.HashUtil; + +/** + * Login Module that works for JBoss SSO. The current implementation uses the + * REST endpoint for authentication. + * The server url can be configured using the 'serverURL' option when + * configuring the JAAS Login Module. + * @author Carlos Munoz camunoz@redhat.com + */ +@Slf4j +public class JBossSSOLoginModule implements LoginModule { + + private CallbackHandler callbackHandler; + private Subject subject; + private Map options; + private String username; + private char[] password; + private String jbossSSOServerUrl = "https://sso.jboss.org"; + private boolean loginSuccessful; + + @Override + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + this.callbackHandler = callbackHandler; + this.subject = subject; + this.options = options; + if (options.containsKey("serverURL")) { + jbossSSOServerUrl = (String) options.get("serverURL"); + } + } + + @Override + public boolean login() throws LoginException { + loginSuccessful = false; + try { + NameCallback cbName = new NameCallback("Enter username"); + PasswordCallback cbPassword = + new PasswordCallback("Enter password", false); + + // Get the username and password from the callback handler + callbackHandler.handle(new Callback[] { cbName, cbPassword }); + username = cbName.getName(); + password = cbPassword.getPassword(); + + // Send the request to JBoss.org's REST service + HttpClient httpClient = new DefaultHttpClient(); + StringBuilder requestUrl = + new StringBuilder(jbossSSOServerUrl + "/rest/auth?"); + String passwordHash = + HashUtil.md5Hex(username + + HashUtil.md5Hex(new String(password))); + requestUrl.append("u=" + username); + requestUrl.append("&h=" + passwordHash); + HttpGet getAuthRequest = new HttpGet(requestUrl.toString()); + + HttpResponse authResponse = httpClient.execute(getAuthRequest); + loginSuccessful = + authResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK; + if (loginSuccessful) { + // read json + ObjectMapper mapper = new ObjectMapper(); + JsonNode parsedResponse = + mapper.readTree(authResponse.getEntity().getContent()); + // TODO These values should be used to pre-populate the + // registration form when a user first registers + //parsedResponse.get("fullname"); + //parsedResponse.get("email"); + log.info("JBoss.org user " + username + + " successfully authenticated"); + } + else { + log.info("JBoss.org user " + username + + " failed authentication"); + } + return loginSuccessful; + } catch (Exception ex) { + LoginException le = new LoginException(ex.getMessage()); + le.initCause(ex); + throw le; + } + } + + @Override + public boolean commit() throws LoginException { + if(!loginSuccessful) { + return false; + } + subject.getPrincipals().add(new SimplePrincipal(username)); + return true; + } + + @Override + public boolean abort() throws LoginException { + return true; + } + + @Override + public boolean logout() throws LoginException { + return true; + } +} diff --git a/zanata-war/src/main/java/org/zanata/security/OpenIdLoginModule.java b/zanata-war/src/main/java/org/zanata/security/OpenIdLoginModule.java index 2184354194..c328a60e8b 100644 --- a/zanata-war/src/main/java/org/zanata/security/OpenIdLoginModule.java +++ b/zanata-war/src/main/java/org/zanata/security/OpenIdLoginModule.java @@ -31,8 +31,7 @@ import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; +import org.zanata.util.ServiceLocator; public class OpenIdLoginModule implements LoginModule { public static final String OPEN_ID_PROVIDER_KEY = "providerURL"; @@ -69,8 +68,7 @@ public boolean login() throws LoginException { callbackHandler.handle(new Callback[] { cbName, cbPassword }); username = cbName.getName(); ZanataOpenId openid = - (ZanataOpenId) Component.getInstance(ZanataOpenId.class, - ScopeType.SESSION); + ServiceLocator.instance().getInstance(ZanataOpenId.class); openid.login(ZanataIdentity.instance().getCredentials()); } catch (Exception ex) { LoginException le = new LoginException(ex.getMessage()); diff --git a/zanata-war/src/main/java/org/zanata/security/SecurityFunctions.java b/zanata-war/src/main/java/org/zanata/security/SecurityFunctions.java index f3cde1c780..e6568cf2fb 100644 --- a/zanata-war/src/main/java/org/zanata/security/SecurityFunctions.java +++ b/zanata-war/src/main/java/org/zanata/security/SecurityFunctions.java @@ -20,14 +20,20 @@ */ package org.zanata.security; -import org.jboss.seam.Component; +import com.google.common.base.Optional; import org.jboss.seam.ScopeType; import org.jboss.seam.security.management.JpaIdentityStore; import org.zanata.dao.PersonDAO; import org.zanata.model.HAccount; import org.zanata.model.HAccountRole; +import org.zanata.model.HIterationGroup; import org.zanata.model.HLocale; +import org.zanata.model.HLocaleMember; +import org.zanata.model.HPerson; import org.zanata.model.HProject; +import org.zanata.model.HProjectIteration; +import org.zanata.security.permission.GrantsPermission; +import org.zanata.util.ServiceLocator; /** * Contains static helper functions used inside the rules files. @@ -39,15 +45,118 @@ public class SecurityFunctions { protected SecurityFunctions() { } + /* admin can do anything */ + @GrantsPermission + public static boolean isAdmin() { + return getIdentity().hasRole("admin"); + } + + public static boolean isProjectMaintainer(HProject project) { + Optional account = getAuthenticatedAccount(); + return account.isPresent() && account.get().getPerson().isMaintainer(project); + } + + /*************************************************************************** + * The Following Rules are for Identity Management + **************************************************************************/ + + @GrantsPermission(actions = "create") + public static boolean canCreateAccount(String target) { + return target.equals("seam.account") && isAdmin(); + } + + @GrantsPermission + public static boolean canManageUsers(String target) { + return target.equals("seam.user") && isAdmin(); + } + + @GrantsPermission + public static boolean canManageRoles(String target) { + return target.equals("seam.role") && isAdmin(); + } + + /*************************************************************************** + * Project ownership rules + **************************************************************************/ + + /* Any authenticated user can create a project */ + @GrantsPermission(actions = "insert") + public static boolean canCreateProject(HProject target) { + return getIdentity().isLoggedIn(); + } + + /* anyone can read a project */ + @GrantsPermission(actions = "read") + public static boolean canReadProject(HProject target) { + return true; + } + + /* anyone can read a project iteration */ + @GrantsPermission(actions = "read") + public static boolean canReadProjectIteration(HProjectIteration target) { + return true; + } + + /* + * Project maintainers may edit (but not delete) a project, or add an + * iteration. Note that 'add-iteration' (on a project) should be granted in + * the same circumstances that 'insert' is granted (on an iteration). In + * other words, make sure the rules agree with each other. (NB: + * 'add-iteration' is used in the UI to enable buttons etc, without + * requiring the construction of HProjectIteration just to do a permission + * check.) + */ + @GrantsPermission(actions = { "update", + "add-iteration" }) + public static boolean canUpdateProjectOrAddIteration(HProject project) { + if (!getIdentity().isLoggedIn()) { + return false; + } + + return isProjectMaintainer(project); + } + + /* + * Project maintainers may create or edit (but not delete) a project + * iteration + */ + @GrantsPermission(actions = { + "insert", "update", "import-template" }) + public static boolean canInsertOrUpdateProjectIteration( + HProjectIteration iteration) { + return isProjectMaintainer(iteration.getProject()); + } + + /*************************************************************************** + * Translation rules + **************************************************************************/ + + /* Language Team members can add a translation for their language teams */ + @GrantsPermission(actions = { "add-translation", "modify-translation" }) + public static boolean canTranslate(HProject project, HLocale lang) { + return isUserAllowedAccess(project) && isUserTranslatorOfLanguage(lang); + } + + public static boolean isUserTranslatorOfLanguage(HLocale lang) { + Optional authenticatedAccount = getAuthenticatedAccount(); + PersonDAO personDAO = + ServiceLocator.instance().getInstance(PersonDAO.class); + + if (authenticatedAccount.isPresent()) { + return personDAO.isUserInLanguageTeamWithRoles( + authenticatedAccount.get().getPerson(), lang, true, null, null); + } + + return false; // No authenticated user + } + public static boolean isUserAllowedAccess(HProject project) { if (project.isRestrictedByRoles()) { ZanataIdentity identity = getIdentity(); - if (identity != null) { - for (HAccountRole role : project.getAllowedRoles()) { - if (identity.hasRole(role.getName())) { - return true; - } + for (HAccountRole role : project.getAllowedRoles()) { + if (identity.hasRole(role.getName())) { + return true; } } @@ -58,65 +167,226 @@ public static boolean isUserAllowedAccess(HProject project) { } } - public static boolean isUserTranslatorOfLanguage(HLocale lang) { - HAccount authenticatedAccount = getAuthenticatedAccount(); + /*************************************************************************** + * Review translation rules + **************************************************************************/ + /* Language Team reviewer can approve/reject translation */ + // TODO Unify these two permission actions into a single one + @GrantsPermission( + actions = { "review-translation", "translation-review" }) + public static boolean + canReviewTranslation(HProject project, HLocale locale) { + return isUserAllowedAccess(project) && isUserReviewerOfLanguage(locale); + } + + public static boolean isUserReviewerOfLanguage(HLocale lang) { + Optional authenticatedAccount = getAuthenticatedAccount(); PersonDAO personDAO = - (PersonDAO) Component.getInstance(PersonDAO.class); + ServiceLocator.instance().getInstance(PersonDAO.class); - if (authenticatedAccount != null) { + if (authenticatedAccount.isPresent()) { return personDAO.isUserInLanguageTeamWithRoles( - authenticatedAccount.getPerson(), lang, true, null, null); + authenticatedAccount.get().getPerson(), lang, null, true, null); + } else { + return false; } - return false; // No authenticated user } - public static boolean isUserReviewerOfLanguage(HLocale lang) { - HAccount authenticatedAccount = getAuthenticatedAccount(); + /* + * Project Maintainers can add, modify or review a translation for their + * projects + */ + @GrantsPermission(actions = { "add-translation", "modify-translation", + "review-translation", "translation-review" }) + public static boolean canAddOrReviewTranslation( + HProject project, HLocale locale) { + Optional authenticatedAccount = getAuthenticatedAccount(); + return authenticatedAccount.isPresent() && isProjectMaintainer(project); + } + + /* Project Maintainer can import translation (merge type is IMPORT) */ + @GrantsPermission(actions = "import-translation") + public static boolean canImportTranslation( + HProjectIteration projectIteration) { + Optional account = getAuthenticatedAccount(); + return account.isPresent() && account.get().getPerson().isMaintainer(projectIteration.getProject()); + } + + public static boolean isLanguageTeamMember(HLocale lang) { + Optional authenticatedAccount = getAuthenticatedAccount(); PersonDAO personDAO = - (PersonDAO) Component.getInstance(PersonDAO.class); + ServiceLocator.instance().getInstance(PersonDAO.class); - if (authenticatedAccount != null) { + if (authenticatedAccount.isPresent()) { return personDAO.isUserInLanguageTeamWithRoles( - authenticatedAccount.getPerson(), lang, null, true, null); + authenticatedAccount.get().getPerson(), lang, null, null, null); + } else { + return false; } - return false; // No authenticated user } + /*************************************************************************** + * Glossary rules + **************************************************************************/ + + /* 'glossarist' can push and update glossaries */ + @GrantsPermission(actions = { "glossary-insert", "glossary-update" }) + public static boolean canPushGlossary() { + return getIdentity().hasRole("glossarist"); + } + + /* 'glossarist-admin' can also delete */ + @GrantsPermission(actions = { "glossary-insert", "glossary-update", + "glossary-delete" }) + public static boolean canAdminGlossary() { + return getIdentity().hasRole("glossary-admin"); + } + + /*************************************************************************** + * Language Team Coordinator rules + **************************************************************************/ + + /* Anyone can read Locale members */ + @GrantsPermission(actions = "read") + public static boolean canSeeLocaleMembers(HLocaleMember localeMember) { + return true; + } + + /* 'team coordinator' can manage language teams */ + @GrantsPermission(actions = "manage-language-team") public static boolean isUserCoordinatorOfLanguage(HLocale lang) { - HAccount authenticatedAccount = getAuthenticatedAccount(); + Optional authenticatedAccount = getAuthenticatedAccount(); PersonDAO personDAO = - (PersonDAO) Component.getInstance(PersonDAO.class); + ServiceLocator.instance().getInstance(PersonDAO.class); - if (authenticatedAccount != null) { + if (authenticatedAccount.isPresent()) { return personDAO.isUserInLanguageTeamWithRoles( - authenticatedAccount.getPerson(), lang, null, null, true); + authenticatedAccount.get().getPerson(), lang, null, null, true); + } else { + return false; } - return false; // No authenticated user } - public static boolean isLanguageTeamMember(HLocale lang) { - HAccount authenticatedAccount = getAuthenticatedAccount(); - PersonDAO personDAO = - (PersonDAO) Component.getInstance(PersonDAO.class); + /* 'team coordinator' can insert/update/delete language team members */ + @GrantsPermission(actions = { "insert", "update", "delete" }) + public static boolean canModifyLanguageTeamMembers( + HLocaleMember localeMember) { + return isUserCoordinatorOfLanguage(localeMember.getSupportedLanguage()); + } - if (authenticatedAccount != null) { - return personDAO.isUserInLanguageTeamWithRoles( - authenticatedAccount.getPerson(), lang, null, null, null); - } + /*************************************************************************** + * View Obsolete Project and Project Iteration rules + **************************************************************************/ - return false; // No authenticated user + // Only admin can view obsolete projects + @GrantsPermission(actions = "view-obsolete") + public static boolean canViewObsoleteProject(HProject project) { + return getIdentity().hasRole("admin"); + } + + // Only admin can view obsolete project iterations + @GrantsPermission(actions = "view-obsolete") + public static boolean canViewObsoleteProjectIteration( + HProjectIteration projectIteration) { + return getIdentity().hasRole("admin"); + } + + /*************************************************************************** + * Mark Project and Project Iteration obsolete rules + **************************************************************************/ + + // Only admin can archive projects + @GrantsPermission(actions = "mark-obsolete") + public static boolean canArchiveProject(HProject project) { + return getIdentity().hasRole("admin"); + } + + // Only admin can archive project iterations + @GrantsPermission(actions = "mark-obsolete") + public static boolean canArchiveProjectIteration( + HProjectIteration projectIteration) { + return getIdentity().hasRole("admin"); + } + + /*************************************************************************** + * File Download rules + **************************************************************************/ + + /* + * Permissions to download files. NOTE: Currently any authenticated user can + * download files + */ + @GrantsPermission(actions = { "download-single", "download-all" }) + public static boolean canDownloadFiles(HProjectIteration projectIteration) { + return getIdentity().isLoggedIn(); + } + + /*************************************************************************** + * Version Group rules + **************************************************************************/ + @GrantsPermission(actions = "update") + public static boolean canUpdateVersionGroup(HIterationGroup group) { + Optional account = getAuthenticatedAccount(); + return account.isPresent() && account.get().getPerson().isMaintainer(group); + } + + @GrantsPermission(actions = "insert") + public static boolean canInsertVersionGroup(HIterationGroup group) { + return isAdmin(); + } + + @GrantsPermission(actions = "view-obsolete") + public static boolean canViewObsoleteVersionGroup(HIterationGroup group) { + return isAdmin(); + } + + /*************************************************************************** + * Copy Trans rules + **************************************************************************/ + + /** Admins and Project maintainers can perform copy-trans */ + @GrantsPermission(actions = "copy-trans") + public static boolean canRunCopyTrans(HProjectIteration iteration) { + Optional account = getAuthenticatedAccount(); + return account.isPresent() && account.get().getPerson().isMaintainer(iteration.getProject()); + } + + /***************************************************************************************** + * Review comment rules + ******************************************************************************************/ + + @GrantsPermission(actions = "review-comment") + public static boolean canCommentOnReview(HLocale locale, HProject project) { + return isUserAllowedAccess(project) && isLanguageTeamMember(locale); + } + + @GrantsPermission(actions = "review-comment") + public static boolean canMaintainerCommentOnReview(HLocale locale, + HProject project) { + Optional account = getAuthenticatedAccount(); + return account.isPresent() && account.get().getPerson().isMaintainer(project); } private static final ZanataIdentity getIdentity() { - return (ZanataIdentity) Component.getInstance(ZanataIdentity.class, - ScopeType.SESSION); + return ServiceLocator.instance().getInstance(ZanataIdentity.class); + } + + private static final Optional getAuthenticatedAccount() { + return Optional.fromNullable(ServiceLocator.instance().getInstance( + JpaIdentityStore.AUTHENTICATED_USER, ScopeType.SESSION, + HAccount.class)); } - private static final HAccount getAuthenticatedAccount() { - return (HAccount) Component.getInstance( - JpaIdentityStore.AUTHENTICATED_USER, ScopeType.SESSION); + private static final T extractTarget(Object[] array, Class type) { + for (int i = 0; i < array.length; i++) { + Object arrayElement = array[i]; + if (type.isAssignableFrom(arrayElement.getClass())) { + return (T) arrayElement; + } + } + return null; } } diff --git a/zanata-war/src/main/java/org/zanata/security/SpNegoIdentity.java b/zanata-war/src/main/java/org/zanata/security/SpNegoIdentity.java index 3dcf51fc2c..54873f28c8 100644 --- a/zanata-war/src/main/java/org/zanata/security/SpNegoIdentity.java +++ b/zanata-war/src/main/java/org/zanata/security/SpNegoIdentity.java @@ -28,8 +28,6 @@ import javax.faces.context.FacesContext; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; @@ -39,6 +37,7 @@ import org.jboss.security.SecurityContextAssociation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.zanata.util.ServiceLocator; @Name("org.jboss.seam.security.spNegoIdentity") @Scope(SESSION) @@ -53,8 +52,7 @@ public class SpNegoIdentity implements Serializable { public void authenticate() { ZanataIdentity identity = - (ZanataIdentity) Component.getInstance(ZanataIdentity.class, - ScopeType.SESSION); + ServiceLocator.instance().getInstance(ZanataIdentity.class); if (identity.isLoggedIn()) { if (Events.exists()) { Events.instance().raiseEvent(Identity.EVENT_ALREADY_LOGGED_IN); @@ -84,8 +82,7 @@ public void authenticate() { public void login() { try { ZanataIdentity identity = - (ZanataIdentity) Component.getInstance( - ZanataIdentity.class, ScopeType.SESSION); + ServiceLocator.instance().getInstance(ZanataIdentity.class); if (identity.isLoggedIn()) { if (Events.exists()) { Events.instance().raiseEvent( diff --git a/zanata-war/src/main/java/org/zanata/security/ZanataIdentity.java b/zanata-war/src/main/java/org/zanata/security/ZanataIdentity.java index a4ee94ac8f..72eb1a1b10 100644 --- a/zanata-war/src/main/java/org/zanata/security/ZanataIdentity.java +++ b/zanata-war/src/main/java/org/zanata/security/ZanataIdentity.java @@ -20,16 +20,10 @@ */ package org.zanata.security; -import java.util.ArrayList; -import java.util.List; import javax.annotation.Nullable; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; -import org.drools.FactHandle; -import org.drools.StatefulSession; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Observer; @@ -42,11 +36,12 @@ import org.jboss.seam.security.Identity; import org.jboss.seam.security.NotLoggedInException; import org.jboss.seam.security.management.JpaIdentityStore; -import org.jboss.seam.security.permission.RuleBasedPermissionResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; import org.zanata.model.HAccount; +import org.zanata.security.permission.MultiTargetList; +import org.zanata.util.ServiceLocator; import static org.jboss.seam.ScopeType.SESSION; import static org.jboss.seam.annotations.Install.APPLICATION; @@ -89,8 +84,7 @@ public static ZanataIdentity instance() { } ZanataIdentity instance = - (ZanataIdentity) Component.getInstance(ZanataIdentity.class, - ScopeType.SESSION); + ServiceLocator.instance().getInstance(ZanataIdentity.class); if (instance == null) { throw new IllegalStateException("No Identity could be created"); @@ -137,9 +131,9 @@ public boolean hasPermission(String name, String action, Object... arg) { } /** - * Indicates if the user has permissions on a variable number of facts. This - * method is a utility provision for Seam's lack of multi-fact insertion - * into working memory. + * Indicates if the user has permission to perform an action on a variable + * number of targets. This is provided as an extension to Seam's single + * target permission capabilities. * * @param action * The permission action. @@ -147,65 +141,25 @@ public boolean hasPermission(String name, String action, Object... arg) { * Targets for permissions. */ public boolean hasPermission(String action, Object... targets) { - final List handles = new ArrayList(); - StatefulSession securityContext = - RuleBasedPermissionResolver.instance().getSecurityContext(); - - synchronized (securityContext) { - // First target - Object firstTarget = targets.length > 0 ? targets[0] : null; - - // Insert the rest of the targets into working memory - for (int i = 1; i < targets.length; i++) { - handles.add(securityContext.insert(targets[i])); - } - - // Run the permission check - boolean result = super.hasPermission(firstTarget, action); - - // Retract all inserted targets - for (FactHandle handle : handles) { - securityContext.retract(handle); - } - - return result; - } + return super + .hasPermission(MultiTargetList.fromTargets(targets), action); } /** - * Checks permissions on a variable number of facts. This method is a - * utility provision for Seam's lack of multi-fact insertion into working - * memory. + * Checks permissions on a variable number of targets.This is provided as an + * extension to Seam's single target permission capabilities. * * @param action * The permission action. * @param targets * Targets for permissions. - * @throws NotLoggedInException if not authorised and not logged in - * @throws org.jboss.seam.security.AuthorizationException if logged in but not authorised + * @throws NotLoggedInException + * if not authorised and not logged in + * @throws org.jboss.seam.security.AuthorizationException + * if logged in but not authorised */ public void checkPermission(String action, Object... targets) { - final List handles = new ArrayList(); - StatefulSession securityContext = - RuleBasedPermissionResolver.instance().getSecurityContext(); - - synchronized (securityContext) { - // First target - Object firstTarget = targets.length > 0 ? targets[0] : null; - - // Insert the rest of the targets into working memory - for (int i = 1; i < targets.length; i++) { - handles.add(securityContext.insert(targets[i])); - } - - // Run the permission check - super.checkPermission(firstTarget, action); - - // Retract all inserted targets - for (FactHandle handle : handles) { - securityContext.retract(handle); - } - } + super.checkPermission(MultiTargetList.fromTargets(targets), action); } @Override @@ -259,8 +213,8 @@ public String login(AuthenticationType authType) { @Nullable public String getAccountUsername() { HAccount authenticatedAccount = - (HAccount) Component - .getInstance(JpaIdentityStore.AUTHENTICATED_USER); + ServiceLocator.instance().getInstance( + JpaIdentityStore.AUTHENTICATED_USER, HAccount.class); if (authenticatedAccount != null) { return authenticatedAccount.getUsername(); } diff --git a/zanata-war/src/main/java/org/zanata/security/ZanataJpaIdentityStore.java b/zanata-war/src/main/java/org/zanata/security/ZanataJpaIdentityStore.java index e345375539..e20f488b32 100644 --- a/zanata-war/src/main/java/org/zanata/security/ZanataJpaIdentityStore.java +++ b/zanata-war/src/main/java/org/zanata/security/ZanataJpaIdentityStore.java @@ -20,7 +20,6 @@ */ package org.zanata.security; -import org.jboss.seam.Component; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; @@ -37,6 +36,7 @@ import org.jboss.seam.util.AnnotatedBeanProperty; import org.zanata.dao.AccountDAO; import org.zanata.model.type.UserApiKey; +import org.zanata.util.ServiceLocator; import static org.jboss.seam.ScopeType.APPLICATION; @@ -158,7 +158,7 @@ public boolean isNewUser(String username) { // also look in the credentials table if (user == null) { AccountDAO accountDAO = - (AccountDAO) Component.getInstance(AccountDAO.class); + ServiceLocator.instance().getInstance(AccountDAO.class); user = accountDAO.getByCredentialsId(username); } return user == null; diff --git a/zanata-war/src/main/java/org/zanata/security/ZanataOpenId.java b/zanata-war/src/main/java/org/zanata/security/ZanataOpenId.java index 2fcccacfdc..f45bb65189 100644 --- a/zanata-war/src/main/java/org/zanata/security/ZanataOpenId.java +++ b/zanata-war/src/main/java/org/zanata/security/ZanataOpenId.java @@ -27,8 +27,6 @@ import javax.faces.context.ExternalContext; import javax.servlet.http.HttpServletRequest; -import org.jboss.seam.Component; -import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.In; @@ -43,7 +41,6 @@ import org.jboss.seam.security.Identity; import org.jboss.seam.security.openid.OpenIdPrincipal; import org.openid4java.OpenIDException; -import org.openid4java.consumer.ConsumerException; import org.openid4java.consumer.ConsumerManager; import org.openid4java.consumer.VerificationResult; import org.openid4java.discovery.DiscoveryInformation; @@ -65,6 +62,7 @@ import org.zanata.security.openid.OpenIdProvider; import org.zanata.security.openid.OpenIdProviderType; import org.zanata.security.openid.YahooOpenIdProvider; +import org.zanata.util.ServiceLocator; @Name("org.jboss.seam.security.zanataOpenId") @Scope(SESSION) @@ -233,10 +231,9 @@ public void init() { authResult = new OpenIdAuthenticationResult(); // TODO inject these identity = - (ZanataIdentity) Component.getInstance(ZanataIdentity.class, - ScopeType.SESSION); + ServiceLocator.instance().getInstance(ZanataIdentity.class); applicationConfiguration = - (ApplicationConfiguration) Component.getInstance( + ServiceLocator.instance().getInstance( ApplicationConfiguration.class); } diff --git a/zanata-war/src/main/java/org/zanata/annotation/CachedMethodResult.java b/zanata-war/src/main/java/org/zanata/security/permission/Action.java similarity index 76% rename from zanata-war/src/main/java/org/zanata/annotation/CachedMethodResult.java rename to zanata-war/src/main/java/org/zanata/security/permission/Action.java index 1d65c4744c..fe92997b3b 100644 --- a/zanata-war/src/main/java/org/zanata/annotation/CachedMethodResult.java +++ b/zanata-war/src/main/java/org/zanata/security/permission/Action.java @@ -18,24 +18,22 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF * site: http://www.fsf.org. */ -package org.zanata.annotation; +package org.zanata.security.permission; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.jboss.seam.ScopeType; - /** - * Annotates methods that wish their results cached within a given context. - * Method return values will be cached by class name, method name and parameter - * values. + * Marks a permission method's (one which is annotated with + * {@link GrantsPermission}) parameter as the + * injection point for the action string into the method invocation. * - * @author camunoz@redhat.com + * @author Carlos Munoz camunoz@redhat.com */ -@Target(ElementType.METHOD) +@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) -public @interface CachedMethodResult { - ScopeType value() default ScopeType.PAGE; +public @interface Action { } diff --git a/zanata-war/src/main/java/org/zanata/security/permission/CustomPermissionResolver.java b/zanata-war/src/main/java/org/zanata/security/permission/CustomPermissionResolver.java new file mode 100644 index 0000000000..0e14621de7 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/security/permission/CustomPermissionResolver.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.security.permission; + +import static org.jboss.seam.ScopeType.APPLICATION; +import static org.jboss.seam.annotations.Install.BUILT_IN; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.Set; + +import org.jboss.seam.annotations.Install; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; +import org.jboss.seam.annotations.Startup; +import org.jboss.seam.annotations.intercept.BypassInterceptors; +import org.jboss.seam.security.permission.PermissionResolver; +import org.zanata.util.ServiceLocator; + +/** + * This permission resolver will use the + * {@link org.zanata.security.permission.PermissionEvaluator} component to + * resolve permissions using java methods annotated with + * {@link GrantsPermission}. + * + * @author Carlos Munoz camunoz@redhat.com + */ +@Name("customPermissionResolver") +@Scope(APPLICATION) +@BypassInterceptors +@Install(precedence = BUILT_IN) +@Startup +public class CustomPermissionResolver implements PermissionResolver, + Serializable { + + @Override + public boolean hasPermission(Object target, String action) { + Object[] targetArray; + if (target instanceof MultiTargetList) { + targetArray = ((MultiTargetList) target).toArray(); + } + else { + targetArray = new Object[] { target }; + } + + return hasPermission(action, targetArray); + } + + private boolean hasPermission(String action, Object... targets) { + PermissionEvaluator evaluator = + ServiceLocator.instance() + .getInstance(PermissionEvaluator.class); + return evaluator.checkPermission(action, targets); + } + + @Override + public void filterSetByAction(Set targets, String action) { + Iterator iter = targets.iterator(); + while (iter.hasNext()) { + Object target = iter.next(); + if (hasPermission(target, action)) + iter.remove(); + } + } +} diff --git a/zanata-war/src/main/java/org/zanata/annotation/CachedMethods.java b/zanata-war/src/main/java/org/zanata/security/permission/GrantsPermission.java similarity index 71% rename from zanata-war/src/main/java/org/zanata/annotation/CachedMethods.java rename to zanata-war/src/main/java/org/zanata/security/permission/GrantsPermission.java index ee74b65e17..6f089910ff 100644 --- a/zanata-war/src/main/java/org/zanata/annotation/CachedMethods.java +++ b/zanata-war/src/main/java/org/zanata/security/permission/GrantsPermission.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, Red Hat, Inc. and individual contributors as indicated by the + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the * @author tags. See the copyright.txt file in the distribution for a full * listing of individual contributors. * @@ -18,25 +18,22 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF * site: http://www.fsf.org. */ -package org.zanata.annotation; +package org.zanata.security.permission; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.jboss.seam.annotations.intercept.Interceptors; -import org.zanata.seam.interceptor.CachedMethodResultInterceptor; - /** - * Type annotation that indicates that a class' methods are candidates for - * result caching. + * Annotates a method as resolving a permission for an optionally provided + * list of action names. * - * @author camunoz@redhat.com + * @author Carlos Munoz camunoz@redhat.com */ -@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -@Interceptors(CachedMethodResultInterceptor.class) -public @interface CachedMethods { - +@Target(ElementType.METHOD) +public @interface GrantsPermission { + String[] actions() default {}; } diff --git a/zanata-war/src/main/java/org/zanata/security/permission/MultiTargetList.java b/zanata-war/src/main/java/org/zanata/security/permission/MultiTargetList.java new file mode 100644 index 0000000000..5aed1a5858 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/security/permission/MultiTargetList.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.security.permission; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * This class encupasulates calls to Seam's permission resolver chain when there + * are multiple targets. Instances of this class will be expanded in the + * {@link org.zanata.security.permission.CustomPermissionResolver} if it's in + * the resolver chain. This class should not be used directly. + * + * @author Carlos Munoz camunoz@redhat.com + */ +public class MultiTargetList extends ArrayList { + + public static MultiTargetList fromTargets(Object ... targets) { + MultiTargetList newInstance = new MultiTargetList(); + newInstance.addAll(Arrays.asList(targets)); + return newInstance; + } +} diff --git a/zanata-war/src/main/java/org/zanata/security/permission/PermissionEvaluator.java b/zanata-war/src/main/java/org/zanata/security/permission/PermissionEvaluator.java new file mode 100644 index 0000000000..0d6acde36d --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/security/permission/PermissionEvaluator.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.security.permission; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.List; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import org.apache.commons.lang.ArrayUtils; +import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.Create; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; +import org.jboss.seam.annotations.Startup; +import org.zanata.security.SecurityFunctions; + +import com.google.common.collect.Lists; + +/** + * Holds all application permissions and provides a way to evaluate these + * permissions for an object and an action. + * + * @author Carlos Munoz camunoz@redhat.com + */ +@Name("permissions") +@AutoCreate +@Scope(ScopeType.APPLICATION) +@Startup +public class PermissionEvaluator { + + private static final String ALL_ACTION_GRANTER = "__**__"; + + private final Multimap permissionGrantMethods = + ArrayListMultimap.create(); + + @Create + public void buildIndex() { + registerPermissionGranters(SecurityFunctions.class); + } + + /** + * Registers all permission granter methods found in clazz to be used to + * check permissions. + * + * @param clazz + */ + public void registerPermissionGranters(Class clazz) { + for (Method m : clazz.getDeclaredMethods()) { + if (m.isAnnotationPresent(GrantsPermission.class)) { + PermissionGranter granter = new PermissionGranter(m); + granter.validate(); + + if (granter.getEvaluatedActions().size() == 0) { + // This granter is to apply to every action + permissionGrantMethods.put(ALL_ACTION_GRANTER, granter); + } else { + for (String action : granter.getEvaluatedActions()) { + permissionGrantMethods.put(action, granter); + } + } + } + } + } + + /** + * Checks a permission for a given action on a set of targets. + * + * @param action + * The action to perform. + * @param targets + * The target object instances to perform the action on. + * @return True, if the permission has been granted. False otherwise. + */ + public boolean checkPermission(String action, Object... targets) { + boolean permissionGranted = false; + // Get granters for all actions (those with no declared action) + Collection allActionGranters = + permissionGrantMethods.get(ALL_ACTION_GRANTER); + for (PermissionGranter granter : allActionGranters) { + if (granter.shouldInvokeGranter(targets)) { + if (granter.invoke(action, targets)) { + return true; + } + } + } + + // Get granters for specific actions + Collection actionGranters = + permissionGrantMethods.get(action); + for (PermissionGranter granter : actionGranters) { + if (granter.shouldInvokeGranter(targets)) { + if (granter.invoke(action, targets)) { + return true; + } + } + } + return false; + } +} diff --git a/zanata-war/src/main/java/org/zanata/security/permission/PermissionGranter.java b/zanata-war/src/main/java/org/zanata/security/permission/PermissionGranter.java new file mode 100644 index 0000000000..3e3dec1dc3 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/security/permission/PermissionGranter.java @@ -0,0 +1,172 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the + * @author tags. See the copyright.txt file in the distribution for a full + * listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this software; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF + * site: http://www.fsf.org. + */ +package org.zanata.security.permission; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.List; + +import com.google.common.collect.Lists; +import lombok.Getter; + +/** + * Represents a function that grants a permission. + * + * @author Carlos Munoz camunoz@redhat.com + */ +public class PermissionGranter { + + private final Method granterMethod; + + @Getter + private Collection evaluatedActions; + + @Getter + private List> acceptedParameterTypes; + + private int actionParameterIndex = -1; + + public PermissionGranter(Method granterMethod) { + this.granterMethod = granterMethod; + this.populateFields(); + } + + /** + * Validates that the permission granter satisfies all preconditions. + */ + public void validate() { + if (!Modifier.isStatic(granterMethod.getModifiers())) { + throw new RuntimeException("Permission method " + + granterMethod.getName() + " must be static"); + } else if (granterMethod.getReturnType() != Boolean.class && + granterMethod.getReturnType() != boolean.class) { + throw new RuntimeException("Permission method " + + granterMethod.getName() + " must return a Boolean type"); + } + } + + private void populateFields() { + GrantsPermission grantAnn = + granterMethod.getAnnotation(GrantsPermission.class); + evaluatedActions = Lists.newArrayList(grantAnn.actions()); + acceptedParameterTypes = + Lists.newArrayList(granterMethod.getParameterTypes()); + + Annotation[][] granterParamAnns = + granterMethod.getParameterAnnotations(); + for (int i = 0; i < acceptedParameterTypes.size(); i++) { + if (acceptedParameterTypes.get(i) == String.class + && containsActionAnnotation(granterParamAnns[i])) { + actionParameterIndex = i; + break; // Only one action parameter index is allowed + } + } + } + + private boolean containsActionAnnotation(Annotation[] annotations) { + for (Annotation a : annotations) { + if (a instanceof Action) { + return true; + } + } + return false; + } + + /** + * Determines whether the granter should be invoked for the given targets. + * + * @param targets + * Permission check targets + * @return True if the granter should be invoked for the given set of + * targets. + */ + public boolean shouldInvokeGranter(Object ... targets) { + // Only invoke the granter if all its parameters can be provided + int paramIdx = 0; + for (Class paramType : acceptedParameterTypes) { + boolean foundParameter = false; + if (paramIdx == actionParameterIndex && paramType == String.class) { + foundParameter = true; // Action parameter can always be + // injected + } else { + for (Object t : targets) { + if (t != null && paramType.isAssignableFrom(t.getClass())) { + foundParameter = true; + break; + } + } + } + // If a matching parameter cannot be found, then the granter will + // not + // be executed + if (!foundParameter) { + return false; + } + paramIdx++; + } + return true; + } + + /** + * Invokes the granter. + * + * @param action + * The action that is being checked for permissions. + * @param targets + * The target object instances that the action will apply to. + * @return True, if the permission to perform the action on the targets has + * been granted. False otherwise. + */ + public boolean invoke(String action, Object ... targets) { + Object[] granterParams = new Object[acceptedParameterTypes.size()]; + int paramIdx = 0; + for (Class paramType : acceptedParameterTypes) { + if (paramIdx == actionParameterIndex) { + // Inject the action + granterParams[paramIdx] = action; + } else { + granterParams[paramIdx] = + findParameterForClass(targets, paramType); + } + paramIdx++; + } + + try { + return (Boolean) granterMethod.invoke(null, granterParams); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private Object findParameterForClass(Object[] params, Class paramType) { + for (Object p : params) { + if (p.getClass() == paramType) + return p; + } + return null; + } +} diff --git a/zanata-war/src/main/java/org/zanata/service/CopyVersionService.java b/zanata-war/src/main/java/org/zanata/service/CopyVersionService.java new file mode 100644 index 0000000000..07294a02ae --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/service/CopyVersionService.java @@ -0,0 +1,107 @@ +/* + * Copyright 2010, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.service; + +import javax.annotation.Nonnull; + +import org.zanata.model.HDocument; +import org.zanata.model.HProjectIteration; +import org.zanata.model.HRawDocument; +import org.zanata.model.HTextFlow; +import org.zanata.model.HTextFlowTarget; + +public interface CopyVersionService { + //@formatter:off + /** + * Perform copy of HProjectIteration in order + * + * 1) Copy version settings + * 2) Copy HDocument (in batch) + * 3) Copy textFlow for each of copied document (in batch) + * 4) Copy textFlowTarget for each of copied textFlow (in batch) + * + * @param projectSlug + * @param versionSlug + * @param newVersionSlug + * + */ + //@formatter:on + void copyVersion(String projectSlug, String versionSlug, + String newVersionSlug); + + /** + * Return total count of HDocument in HProjectIteration + * + * @param projectSlug + * @param versionSlug + */ + int getTotalDocCount(String projectSlug, + String versionSlug); + + /** + * Create copy of HProjectIteration. Excludes properties: "slug", "project", + * "children", "documents", "allDocuments" + * + * @param version + * @param newVersion + */ + HProjectIteration copyVersionSettings( + HProjectIteration version, HProjectIteration newVersion); + + /** + * Create copy of HDocument. Excludes properties: "projectIteration", + * "poHeader", "poTargetHeaders", "rawDocument", "textFlows", "allTextFlows" + * + * @param newVersion + * @param document + */ + HDocument copyDocument(HProjectIteration newVersion, HDocument document) + throws Exception; + + /** + * Create copy of HRawDocument. Excludes properties: "document" + * + * @param newDocument + * @param rawDocument + */ + HRawDocument copyRawDocument(HDocument newDocument, + @Nonnull HRawDocument rawDocument) throws Exception; + + /** + * Create copy of HTextFlow. Excludes properties: "document", "targets", + * "history", "potEntryData" + * + * @param newDocument + * @param textFlow + */ + HTextFlow copyTextFlow(HDocument newDocument, HTextFlow textFlow) + throws Exception; + + /** + * Create copy of HTextFlowTarget with all histories. Excludes properties: + * "textFlow", "reviewComments", "history" + * + * @param textFlow + * @param tft + */ + HTextFlowTarget copyTextFlowTarget(HTextFlow textFlow, + HTextFlowTarget tft) throws Exception; +} diff --git a/zanata-war/src/main/java/org/zanata/service/EmailService.java b/zanata-war/src/main/java/org/zanata/service/EmailService.java index a11c2eb7f5..dfc19dff13 100644 --- a/zanata-war/src/main/java/org/zanata/service/EmailService.java +++ b/zanata-war/src/main/java/org/zanata/service/EmailService.java @@ -22,84 +22,50 @@ import java.util.List; +import org.zanata.email.EmailStrategy; +import org.zanata.model.HLocale; import org.zanata.model.HPerson; /** * @author Alex Eng aeng@redhat.com */ public interface EmailService { - public static final String ADMIN_EMAIL_TEMPLATE = - "/WEB-INF/facelets/email/email_admin.xhtml"; - public static final String COORDINATOR_EMAIL_TEMPLATE = - "/WEB-INF/facelets/email/email_coordinator.xhtml"; - public static final String REQUEST_TO_JOIN_EMAIL_TEMPLATE = - "/WEB-INF/facelets/email/email_request_to_join_language.xhtml"; - public static final String REQUEST_ROLE_EMAIL_TEMPLATE = - "/WEB-INF/facelets/email/email_request_role_language.xhtml"; - public static final String REQUEST_TO_JOIN_GROUP_EMAIL_TEMPLATE = - "/WEB-INF/facelets/email/email_request_to_join_group.xhtml"; - public static final String ACTIVATION_ACCOUNT_EMAIL_TEMPLATE = - "/WEB-INF/facelets/email/activation.xhtml"; /** - * sends emails to configured admin emails for server, or admin users if no - * server emails are configured. - * + * send account activation email to register user * - * @param emailTemplate - * @param fromName - * @param fromLoginName - * @param replyEmail - * @param subject - * @param message + * @param toName + * @param toEmailAddr + * @param activationKey * @return */ - String sendToAdminEmails(String emailTemplate, String fromName, - String fromLoginName, String replyEmail, String subject, - String message); + String sendActivationEmail(String toName, + String toEmailAddr, String activationKey); + + String sendEmailValidationEmail(String toName, + String toEmailAddr, String activationKey); + + String sendPasswordResetEmail(HPerson person, String key); /** - * sends emails to version group maintainers -> admin -> admin users - * - * @param emailTemplate - * @param maintainers - * @param fromName - * @param fromLoginName - * @param replyEmail - * @param subject - * @param message - * @return + * sends emails to configured admin emails for server, or admin users if no + * server emails are configured. */ - String sendToVersionGroupMaintainer(String emailTemplate, - List maintainers, String fromName, String fromLoginName, - String replyEmail, String subject, String message); + String sendToAdmins(EmailStrategy strategy); /** - * sends emails to language coordinators -> admin -> admin users - * - * @param emailTemplate - * @param coordinators - * @param fromName - * @param fromLoginName - * @param replyEmail - * @param subject - * @param message - * @param language - * @return + * sends emails to version group maintainers -> admin -> admin users */ - String sendToLanguageCoordinators(String emailTemplate, - List coordinators, String fromName, String fromLoginName, - String replyEmail, String subject, String message, String language); + String sendToVersionGroupMaintainers(List maintainers, + EmailStrategy strategy); /** - * send account activation email to register user + * sends emails to language coordinators -> admin -> admin users * - * @param emailTemplate - * @param toName - * @param toEmailAddr - * @param activationKey - * @return */ - String sendActivationEmail(String emailTemplate, String toName, - String toEmailAddr, String activationKey); + String sendToLanguageCoordinators(HLocale locale, + EmailStrategy strategy); + + String sendUsernameChangedEmail(String email, String newUsername); + } diff --git a/zanata-war/src/main/java/org/zanata/service/SearchIndexManager.java b/zanata-war/src/main/java/org/zanata/service/SearchIndexManager.java index 6fcd09bab8..dff47658fe 100644 --- a/zanata-war/src/main/java/org/zanata/service/SearchIndexManager.java +++ b/zanata-war/src/main/java/org/zanata/service/SearchIndexManager.java @@ -5,8 +5,10 @@ import java.util.LinkedHashMap; import java.util.List; +import javax.annotation.Nonnull; import javax.persistence.EntityManagerFactory; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.hibernate.Session; @@ -22,7 +24,6 @@ import org.zanata.ServerConstants; import org.zanata.action.ReindexClassOptions; import org.zanata.async.AsyncTask; -import org.zanata.async.AsyncTaskHandle; import org.zanata.async.TimedAsyncHandle; import org.zanata.model.HAccount; import org.zanata.model.HGlossaryEntry; @@ -50,11 +51,9 @@ public class SearchIndexManager implements Serializable { @In AsyncTaskManagerService asyncTaskManagerServiceImpl; - private FullTextSession session; - // we use a list to ensure predictable order - private List> indexables = new ArrayList>(); - private LinkedHashMap, ReindexClassOptions> indexingOptions = + private final List> indexables = new ArrayList>(); + private final LinkedHashMap, ReindexClassOptions> indexingOptions = new LinkedHashMap, ReindexClassOptions>(); private Class currentClass; @@ -62,6 +61,8 @@ public class SearchIndexManager implements Serializable { @Create public void create() { + // TODO get the list of classes from Hibernate Search + // ie FullTextSession.getSearchFactory().getStatistics().getIndexedClassNames() indexables.add(HAccount.class); indexables.add(HGlossaryEntry.class); indexables.add(HGlossaryTerm.class); @@ -123,61 +124,22 @@ public String getCurrentClassName() { return currentClass.getSimpleName(); } - /** - * Returns the number of total operations to perform - */ - private int getTotalOperations() { - session = - Search.getFullTextSession((Session) entityManagerFactory - .createEntityManager().getDelegate()); - - // set up progress counter - int totalOperations = 0; - for (Class clazz : indexables) { - ReindexClassOptions opts = indexingOptions.get(clazz); - if (opts.isPurge()) { - totalOperations++; - } - - if (opts.isReindex()) { - totalOperations += getIndexer(clazz).getEntityCount(); - } - - if (opts.isOptimize()) { - totalOperations++; - } - } - return totalOperations; - } - /** * Facility method to start the background process with this instance's own * internal process handle. */ public void startProcess() { + assert handle == null || handle.isDone(); + final ReindexTask reindexTask = new ReindexTask(entityManagerFactory); String taskId = - asyncTaskManagerServiceImpl.startTask(new ReindexTask()); - this.handle = - (TimedAsyncHandle) asyncTaskManagerServiceImpl - .getHandle(taskId); - } - - @SuppressWarnings("rawtypes") - ClassIndexer getIndexer(Class clazz) { - AbstractIndexingStrategy strategy; - // TODO add a strategy which uses TransMemoryStreamingDAO - if (clazz.equals(HTextFlowTarget.class)) { - strategy = new HTextFlowTargetIndexingStrategy(session); - } else { - strategy = new SimpleClassIndexingStrategy(clazz, session); - } - return new ClassIndexer(session, handle, clazz, strategy); + asyncTaskManagerServiceImpl.startTask(reindexTask); + this.handle = (TimedAsyncHandle) asyncTaskManagerServiceImpl.getHandle(taskId); } public void reindex(boolean purge, boolean reindex, boolean optimize) throws Exception { setOptions(purge, reindex, optimize); - new ReindexTask().call(); + new ReindexTask(entityManagerFactory).call(); } /** @@ -186,71 +148,126 @@ public void reindex(boolean purge, boolean reindex, boolean optimize) */ private class ReindexTask implements AsyncTask> { + private final EntityManagerFactory entityManagerFactory; - private TimedAsyncHandle handle; + @Getter + @Nonnull + private final TimedAsyncHandle handle; - @Override - public TimedAsyncHandle getHandle() { - if (handle == null) { - String name = getClass().getSimpleName(); // +":"+indexingOptions - handle = new TimedAsyncHandle(name); - handle.setMaxProgress(getTotalOperations()); + public ReindexTask(EntityManagerFactory entityManagerFactory) { + this.entityManagerFactory = entityManagerFactory; + String name = getClass().getSimpleName(); // +":"+indexingOptions + this.handle = new TimedAsyncHandle(name); + FullTextSession session = openFullTextSession(); + try { + handle.setMaxProgress(getTotalOperations(session)); + } finally { + session.close(); } - return handle; } - @Override - public Void call() throws Exception { - // TODO this is necessary because isInProgress checks number of - // operations, which may be 0 - // look at updating isInProgress not to care about count - if (getHandle().getMaxProgress() == 0) { - log.info("Reindexing aborted because there are no actions to perform (may be indexing an empty table)"); - return null; - } - getHandle().startTiming(); + private FullTextSession openFullTextSession() { + return Search.getFullTextSession(entityManagerFactory + .createEntityManager().unwrap(Session.class)); + } + + /** + * Returns the number of total operations to perform + */ + private int getTotalOperations(FullTextSession session) { + // set up progress counter + int totalOperations = 0; for (Class clazz : indexables) { - if (!getHandle().isCancelled() - && indexingOptions.get(clazz).isPurge()) { - log.info("purging index for {}", clazz); - currentClass = clazz; - session.purgeAll(clazz); - getHandle().increaseProgress(1); + ReindexClassOptions opts = indexingOptions.get(clazz); + if (opts.isPurge()) { + totalOperations++; } - if (!getHandle().isCancelled() - && indexingOptions.get(clazz).isReindex()) { - log.info("reindexing {}", clazz); - currentClass = clazz; - getIndexer(clazz).index(); + + if (opts.isReindex()) { + totalOperations += getIndexer(clazz).getEntityCount(session); } - if (!getHandle().isCancelled() - && indexingOptions.get(clazz).isOptimize()) { - log.info("optimizing {}", clazz); - currentClass = clazz; - session.getSearchFactory().optimize(clazz); - getHandle().increaseProgress(1); + + if (opts.isOptimize()) { + totalOperations++; } } + return totalOperations; + } - if (getHandle().isCancelled()) { - log.info("index operation canceled by user"); + private ClassIndexer getIndexer(Class clazz) { + AbstractIndexingStrategy strategy; + // TODO add a strategy which uses TransMemoryStreamingDAO + if (clazz.equals(HTextFlowTarget.class)) { + strategy = + (AbstractIndexingStrategy) new HTextFlowTargetIndexingStrategy(); } else { - if (getHandle().getCurrentProgress() != getHandle() - .getMaxProgress()) { - // @formatter: off - log.warn( - "Did not reindex the expected number of objects. Counted {} but indexed {}. " - + "The index may be out-of-sync. " - + "This may be caused by lack of sufficient memory, or by database activity during reindexing.", - getHandle().getMaxProgress(), getHandle() - .getCurrentProgress()); - // @formatter: on + strategy = new SimpleClassIndexingStrategy(clazz); + } + return new ClassIndexer(handle, clazz, strategy); + } + + @Override + public Void call() throws Exception { + FullTextSession session = openFullTextSession(); + try { + handle.setMaxProgress(getTotalOperations(session)); + // TODO this is necessary because isInProgress checks number of + // operations, which may be 0 + // look at updating isInProgress not to care about count + if (getHandle().getMaxProgress() == 0) { + log.info("Reindexing aborted because there are no actions " + + "to perform (may be indexing an empty table)"); + return null; } + getHandle().startTiming(); + for (Class clazz : indexables) { + if (!getHandle().isCancelled() + && indexingOptions.get(clazz).isPurge()) { + log.info("purging index for {}", clazz); + currentClass = clazz; + session.purgeAll(clazz); + getHandle().increaseProgress(1); + } + if (!getHandle().isCancelled() + && indexingOptions.get(clazz).isReindex()) { + log.info("reindexing {}", clazz); + currentClass = clazz; + getIndexer(clazz).index(session); + } + if (!getHandle().isCancelled() + && indexingOptions.get(clazz).isOptimize()) { + log.info("optimizing {}", clazz); + currentClass = clazz; + session.getSearchFactory().optimize(clazz); + getHandle().increaseProgress(1); + } + } + + if (getHandle().isCancelled()) { + log.info("index operation canceled by user"); + } else { + if (getHandle().getCurrentProgress() != getHandle() + .getMaxProgress()) { + // @formatter: off + log.warn( + "Did not reindex the expected number of " + + "objects. Counted {} but indexed {}. " + + "The index may be out-of-sync. " + + "This may be caused by lack of " + + "sufficient memory, or by database " + + "activity during reindexing.", + getHandle().getMaxProgress(), getHandle() + .getCurrentProgress()); + // @formatter: on + } - log.info("Re-indexing finished"); + log.info("Re-indexing finished"); + } + getHandle().finishTiming(); + return null; + } finally { + session.close(); } - getHandle().finishTiming(); - return null; } } } diff --git a/zanata-war/src/main/java/org/zanata/service/impl/ActivityServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/ActivityServiceImpl.java index e1b90ff134..825b62a522 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/ActivityServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/ActivityServiceImpl.java @@ -21,6 +21,7 @@ package org.zanata.service.impl; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.concurrent.locks.Lock; @@ -98,7 +99,7 @@ private Date getRoundedTime(Date actionTime) { public List findLatestVersionActivitiesByUser(long personId, List versionIds, int offset, int maxResults) { if (versionIds.isEmpty()) { - return Lists.newArrayList(); + return Collections.EMPTY_LIST; } return activityDAO.findLatestVersionActivitiesByUser(personId, versionIds, offset, maxResults); diff --git a/zanata-war/src/main/java/org/zanata/service/impl/AsyncTaskManagerServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/AsyncTaskManagerServiceImpl.java index 0a11b3f4bf..947862e2e3 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/AsyncTaskManagerServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/AsyncTaskManagerServiceImpl.java @@ -25,7 +25,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; @@ -34,6 +33,7 @@ import org.zanata.async.AsyncTask; import org.zanata.async.TaskExecutor; import org.zanata.service.AsyncTaskManagerService; +import org.zanata.util.ServiceLocator; import java.io.Serializable; import java.util.Collection; @@ -92,7 +92,7 @@ public > String startTask( public > void startTask( AsyncTask task, final Serializable key) { TaskExecutor taskExecutor = - (TaskExecutor) Component.getInstance(TaskExecutor.class); + ServiceLocator.instance().getInstance(TaskExecutor.class); AsyncTaskHandle handle = taskExecutor.startTask(task, new Runnable() { @Override diff --git a/zanata-war/src/main/java/org/zanata/service/impl/CopyDocumentWork.java b/zanata-war/src/main/java/org/zanata/service/impl/CopyDocumentWork.java new file mode 100644 index 0000000000..15809ad6ec --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/service/impl/CopyDocumentWork.java @@ -0,0 +1,79 @@ +package org.zanata.service.impl; + +import java.util.List; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import org.jboss.seam.util.Work; +import org.zanata.dao.DocumentDAO; +import org.zanata.dao.ProjectIterationDAO; +import org.zanata.file.FilePersistService; +import org.zanata.model.HDocument; +import org.zanata.model.HProjectIteration; +import org.zanata.model.HRawDocument; +import org.zanata.service.CopyVersionService; + +import com.google.common.collect.Maps; + +/** + * Run copy document and persist in transaction. + * + * Copy documents from HProjectIteration(id=versionId) in batches(batchStart, + * batchLength) into HProjectIteration(id=newVersionId). Copying includes + * HRawDocument stored in file system. + * + * @see CopyVersionService#copyDocument + * + * @return Map of original HDocument id => copied HDocument id + * + * @author Alex Eng aeng@redhat.com + */ +@Slf4j +@AllArgsConstructor +public class CopyDocumentWork extends Work> { + + private final Long versionId; + private final Long newVersionId; + private final DocumentDAO documentDAO; + private final ProjectIterationDAO projectIterationDAO; + private final FilePersistService filePersistService; + private final CopyVersionService copyVersionService; + private final int batchStart; + private final int batchLength; + + @Override + protected Map work() throws Exception { + Map docMap = Maps.newHashMap(); + + HProjectIteration newVersion = + projectIterationDAO.findById(newVersionId); + + List documents = documentDAO.findAllByVersionId(versionId, + batchStart, batchLength); + + for (HDocument doc : documents) { + HDocument newDocument = + copyVersionService.copyDocument(newVersion, doc); + // Needs to persist before inserting raw document + newDocument = documentDAO.makePersistent(newDocument); + + if (doc.getRawDocument() != null) { + HRawDocument newRawDocument = + copyVersionService.copyRawDocument(newDocument, + doc.getRawDocument()); + + filePersistService.copyAndPersistRawDocument( + doc.getRawDocument(), newRawDocument); + + documentDAO.addRawDocument(newDocument, newRawDocument); + } + newVersion.getDocuments() + .put(newDocument.getDocId(), newDocument); + docMap.put(doc.getId(), newDocument.getId()); + } + documentDAO.flush(); + return docMap; + } +} diff --git a/zanata-war/src/main/java/org/zanata/service/impl/CopyTextFlowTargetWork.java b/zanata-war/src/main/java/org/zanata/service/impl/CopyTextFlowTargetWork.java new file mode 100644 index 0000000000..21c4fa4a8c --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/service/impl/CopyTextFlowTargetWork.java @@ -0,0 +1,59 @@ +package org.zanata.service.impl; + +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import org.jboss.seam.util.Work; +import org.zanata.dao.TextFlowDAO; +import org.zanata.dao.TextFlowTargetDAO; +import org.zanata.model.HTextFlow; +import org.zanata.model.HTextFlowTarget; +import org.zanata.service.CopyVersionService; + +/** + * Copy text flow target and persist in transaction. + * + * Copy HTextFlowTarget from HTextFlow(id=tfId) in batches(batchStart, + * batchLength) into HTextFlow(id=newTfId). + * + * @see CopyVersionService#copyTextFlowTarget + * + * @return count of HTextFlowTarget copied. + * + * + * @author Alex Eng aeng@redhat.com + */ +@Slf4j +@AllArgsConstructor +public class CopyTextFlowTargetWork extends Work { + private final Long tfId; + private final Long newTfId; + private final TextFlowTargetDAO textFlowTargetDAO; + private final TextFlowDAO textFlowDAO; + private final CopyVersionService copyVersionService; + private final int batchStart; + private final int batchLength; + + @Override + protected Integer work() throws Exception { + HTextFlow newTextFlow = textFlowDAO.findById(newTfId); + + List copyTargets = + textFlowTargetDAO + .getByTextFlowId(tfId, batchStart, batchLength); + + for (HTextFlowTarget tft : copyTargets) { + HTextFlowTarget newTextFlowTarget = + copyVersionService.copyTextFlowTarget(newTextFlow, tft); + + newTextFlow.getTargets() + .put(newTextFlowTarget.getLocale().getId(), + newTextFlowTarget); + } + textFlowDAO.makePersistent(newTextFlow); + textFlowDAO.flush(); + return copyTargets.size(); + } +} diff --git a/zanata-war/src/main/java/org/zanata/service/impl/CopyTextFlowWork.java b/zanata-war/src/main/java/org/zanata/service/impl/CopyTextFlowWork.java new file mode 100644 index 0000000000..02fc6c4a92 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/service/impl/CopyTextFlowWork.java @@ -0,0 +1,72 @@ +package org.zanata.service.impl; + +import java.util.List; +import java.util.Map; + +import org.jboss.seam.util.Work; +import org.zanata.dao.DocumentDAO; +import org.zanata.dao.TextFlowDAO; +import org.zanata.model.HDocument; +import org.zanata.model.HTextFlow; +import org.zanata.service.CopyVersionService; +import com.google.common.collect.Maps; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Run copy text flow and persist in transaction. + * + * Copy HTextFlow from HDocument(id=documentId) in batches(batchStart, + * batchLength) into HDocument(id=newDocumentId). + * + * @see CopyVersionService#copyTextFlow + * + * @return Map of original HTextFlow id => copied HTextFlow id + * + * @author Alex Eng aeng@redhat.com + */ +@Slf4j +@AllArgsConstructor +public class CopyTextFlowWork extends Work> { + + private final Long documentId; + private final Long newDocumentId; + private final TextFlowDAO textFlowDAO; + private final DocumentDAO documentDAO; + private final CopyVersionService copyVersionService; + private final int batchStart; + private final int batchLength; + + private static final Maps.EntryTransformer transformer = + new Maps.EntryTransformer() { + @Override + public Long transformEntry(Long key, HTextFlow value) { + return value.getId(); + } + }; + + @Override + protected Map work() throws Exception { + Map tfMap = Maps.newHashMap(); + + List textFlows = textFlowDAO.getTextFlowsByDocumentId( + documentId, batchStart, batchLength); + + HDocument newDocument = documentDAO.getById(newDocumentId); + for (HTextFlow textFlow : textFlows) { + HTextFlow newTextFlow = + copyVersionService.copyTextFlow(newDocument, + textFlow); + + newDocument.getTextFlows().add(newTextFlow); + newDocument.getAllTextFlows() + .put(newTextFlow.getResId(), newTextFlow); + tfMap.put(textFlow.getId(), newTextFlow); + } + documentDAO.makePersistent(newDocument); + documentDAO.flush(); + + return Maps.transformEntries(tfMap, transformer); + } +} diff --git a/zanata-war/src/main/java/org/zanata/service/impl/CopyVersionServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/CopyVersionServiceImpl.java new file mode 100644 index 0000000000..e96e4b1dec --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/service/impl/CopyVersionServiceImpl.java @@ -0,0 +1,339 @@ +package org.zanata.service.impl; + +import com.google.common.base.Optional; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; +import org.jboss.seam.annotations.In; +import org.jboss.seam.annotations.Name; +import org.jboss.seam.annotations.Scope; +import org.zanata.async.AsyncUtils; +import org.zanata.async.tasks.CopyVersionTask; +import org.zanata.dao.DocumentDAO; +import org.zanata.dao.ProjectIterationDAO; +import org.zanata.dao.TextFlowDAO; +import org.zanata.dao.TextFlowTargetDAO; +import org.zanata.file.FilePersistService; +import org.zanata.model.HDocument; +import org.zanata.model.HLocale; +import org.zanata.model.HProjectIteration; +import org.zanata.model.HRawDocument; +import org.zanata.model.HTextFlow; +import org.zanata.model.HTextFlowTarget; +import org.zanata.model.HTextFlowTargetHistory; +import org.zanata.model.HTextFlowTargetReviewComment; +import org.zanata.model.po.HPoHeader; +import org.zanata.model.po.HPoTargetHeader; +import org.zanata.model.po.HPotEntryData; +import org.zanata.service.CopyVersionService; +import org.zanata.service.VersionStateCache; +import org.zanata.util.JPACopier; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Map; + +/** + * @author Alex Eng aeng@redhat.com + */ +@Name("copyVersionServiceImpl") +@Scope(ScopeType.STATELESS) +@Slf4j +@AutoCreate +public class CopyVersionServiceImpl implements CopyVersionService { + + // Document batch size + protected final static int DOC_BATCH_SIZE = 2; + + // TextFlow batch size + protected final static int TF_BATCH_SIZE = 20; + + // TextFlowTarget batch size + protected final static int TFT_BATCH_SIZE = 20; + + @In + private ProjectIterationDAO projectIterationDAO; + + @In + private DocumentDAO documentDAO; + + @In + private TextFlowDAO textFlowDAO; + + @In + private TextFlowTargetDAO textFlowTargetDAO; + + @In + private VersionStateCache versionStateCacheImpl; + + @In + private FilePersistService filePersistService; + + // Stop watch for textFlow and target copy process + private Stopwatch copyTfAndTftStopWatch = new Stopwatch(); + + @Override + public void copyVersion(@Nonnull String projectSlug, + @Nonnull String versionSlug, @Nonnull String newVersionSlug) { + Stopwatch overallStopwatch = new Stopwatch().start(); + log.info("copy version start: copy {} to {}", + projectSlug + ":" + versionSlug, projectSlug + ":" + + newVersionSlug); + + HProjectIteration version = + projectIterationDAO.getBySlug(projectSlug, versionSlug); + if (version == null) { + log.error("Cannot find project iteration of {}:{}", projectSlug, + versionSlug); + return; + } + + // Copy of HProjectIteration + HProjectIteration newVersion = + projectIterationDAO.getBySlug(projectSlug, newVersionSlug); + + newVersion = copyVersionSettings(version, newVersion); + newVersion = projectIterationDAO.makePersistent(newVersion); + + // Copy of HDocument + Optional taskHandleOpt = + AsyncUtils.getEventAsyncHandle( + CopyVersionTask.CopyVersionTaskHandle.class); + + int docSize = + documentDAO.getDocCountByVersion(projectSlug, versionSlug); + + int docStart = 0; + while (docStart < docSize) { + Map docMap = + copyDocumentBatch(version.getId(), newVersion.getId(), + docStart, DOC_BATCH_SIZE); + docStart += DOC_BATCH_SIZE; + + for (Map.Entry entry : docMap.entrySet()) { + // Copy of HTextFlow and HTextFlowTarget + copyTextFlowAndTarget(entry.getKey(), entry.getValue()); + + if (taskHandleOpt.isPresent()) { + taskHandleOpt.get().incrementDocumentProcessed(); + taskHandleOpt.get().increaseProgress(1); + } + } + } + + // restore version.status after complete + newVersion = projectIterationDAO.getBySlug(projectSlug, newVersionSlug); + newVersion.setStatus(version.getStatus()); + projectIterationDAO.makePersistent(newVersion); + projectIterationDAO.flush(); + + // clear any cache that has been loaded in this new version before copy + // completed + versionStateCacheImpl.clearVersionStatsCache(newVersion.getId()); + log.info("copy version end: copy {} to {}, {}", projectSlug + + ":" + versionSlug, projectSlug + ":" + newVersionSlug, + overallStopwatch); + } + + @Override + public int getTotalDocCount(@Nonnull String projectSlug, + @Nonnull String versionSlug) { + return documentDAO.getDocCountByVersion(projectSlug, versionSlug); + } + + /** + * Return map of old HDocument id, new HDocument id copied + * + * @param versionId + * @param newVersionId + * @param batchStart + * @param batchLength + */ + protected Map copyDocumentBatch(Long versionId, + Long newVersionId, int batchStart, int batchLength) { + try { + return new CopyDocumentWork(versionId, newVersionId, documentDAO, + projectIterationDAO, filePersistService, this, + batchStart, batchLength).workInTransaction(); + } catch (Exception e) { + log.warn("exception during copy document", e); + return Collections.emptyMap(); + } + } + + /** + * Copy text flows and targets of document with id=documentId to document + * with id=newDocumentId + * + * @param documentId + * @param newDocumentId + */ + private void copyTextFlowAndTarget(Long documentId, Long newDocumentId) { + copyTfAndTftStopWatch.start(); + int tfStart = 0, tftStart = 0, totalTftCount = 0; + int tfCount = textFlowDAO.countActiveTextFlowsInDocument(documentId); + + while (tfStart < tfCount) { + Map tfMap = + copyTextFlowBatch(documentId, newDocumentId, tfStart, + TF_BATCH_SIZE); + tfStart += TF_BATCH_SIZE; + textFlowDAO.clear(); + documentDAO.clear(); + + for (Map.Entry entry : tfMap.entrySet()) { + tftStart = 0; + int tftCount = + textFlowTargetDAO.countTextFlowTargetsInTextFlow( + entry.getKey()); + + while (tftStart < tftCount) { + totalTftCount += + copyTextFlowTargetBatch(entry.getKey(), + entry.getValue(), tftStart, TFT_BATCH_SIZE); + tftStart += TFT_BATCH_SIZE; + textFlowDAO.clear(); + textFlowTargetDAO.clear(); + } + } + } + copyTfAndTftStopWatch.stop(); + log.info( + "copy document- textFlow:{}, textFlowTarget:{} copied for document:{} - {}", + tfCount, totalTftCount, newDocumentId, copyTfAndTftStopWatch); + copyTfAndTftStopWatch.reset(); + } + + /** + * Return map of old HTextFlow id, new HTextFlow id copied + * + * @param documentId + * @param newDocumentId + * @param batchStart + * @param batchLength + */ + protected Map copyTextFlowBatch(Long documentId, + Long newDocumentId, int batchStart, int batchLength) { + try { + return new CopyTextFlowWork(documentId, newDocumentId, textFlowDAO, + documentDAO, this, batchStart, batchLength) + .workInTransaction(); + } catch (Exception e) { + log.warn("exception during copy text flow", e); + return Collections.EMPTY_MAP; + } + } + + /** + * Return number of HTextFlowTarget copied + * + * @param tfId + * @param newTfId + * @param batchStart + * @param batchLength + */ + protected int copyTextFlowTargetBatch(Long tfId, Long newTfId, + int batchStart, int batchLength) { + try { + return new CopyTextFlowTargetWork(tfId, newTfId, textFlowTargetDAO, + textFlowDAO, this, batchStart, batchLength) + .workInTransaction(); + } catch (Exception e) { + log.warn("exception during copy text flow target", e); + return 0; + } + } + + @Override + public HProjectIteration copyVersionSettings( + HProjectIteration version, HProjectIteration newVersion) { + try { + JPACopier.copyBean(version, newVersion, "slug", "status", "project", + "children", "documents", "allDocuments"); + } catch (Exception e) { + log.warn("exception during copy version", e); + } + return newVersion; + } + + @Override + public HDocument copyDocument(HProjectIteration newVersion, + HDocument document) throws Exception { + HDocument copy = + JPACopier. copyBean(document, "projectIteration", + "poHeader", "poTargetHeaders", "rawDocument", + "textFlows", "allTextFlows"); + copy.setProjectIteration(newVersion); + + if (document.getPoHeader() != null) { + HPoHeader poHeader = + JPACopier. copyBean(document.getPoHeader()); + copy.setPoHeader(poHeader); + } + + for (Map.Entry entry : document + .getPoTargetHeaders().entrySet()) { + HPoTargetHeader poTargetHeader = + JPACopier. copyBean(entry.getValue(), + "document"); + poTargetHeader.setDocument(copy); + copy.getPoTargetHeaders().put(entry.getKey(), poTargetHeader); + } + return copy; + } + + @Override + public HRawDocument copyRawDocument(HDocument newDocument, + @Nonnull HRawDocument rawDocument) throws Exception { + HRawDocument copy = + JPACopier. copyBean(rawDocument, "document"); + copy.setDocument(newDocument); + return copy; + } + + @Override + public HTextFlow copyTextFlow(HDocument newDocument, HTextFlow textFlow) + throws Exception { + HTextFlow copy = + JPACopier. copyBean(textFlow, "document", "content", + "targets", "history", "potEntryData"); + copy.setDocument(newDocument); + + // copy PotEntryData + if (textFlow.getPotEntryData() != null) { + HPotEntryData potEntryData = JPACopier. copyBean( + textFlow.getPotEntryData(), "textFlow"); + copy.setPotEntryData(potEntryData); + } + return copy; + } + + @Override + public HTextFlowTarget copyTextFlowTarget(HTextFlow newTf, + HTextFlowTarget tft) throws Exception { + HTextFlowTarget copy = + JPACopier. copyBean(tft, "textFlow", + "reviewComments", "history"); + copy.setTextFlow(newTf); + copy.setTextFlowRevision(newTf.getRevision()); + + // copy review comment + copy.setReviewComments(Lists + . newArrayList()); + for (HTextFlowTargetReviewComment comment : tft.getReviewComments()) { + copy.addReviewComment(comment.getComment(), comment.getCommenter()); + } + + // copy history + for (HTextFlowTargetHistory history : tft.getHistory().values()) { + HTextFlowTargetHistory newHistory = + JPACopier. copyBean(history, + "textFlowTarget"); + newHistory.setTextFlowTarget(copy); + copy.getHistory().put(newHistory.getVersionNum(), newHistory); + } + return copy; + } +} diff --git a/zanata-war/src/main/java/org/zanata/service/impl/DocumentStateCacheImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/DocumentStateCacheImpl.java index c995ff8bbb..eb30e5de50 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/DocumentStateCacheImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/DocumentStateCacheImpl.java @@ -27,7 +27,6 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import net.sf.ehcache.CacheManager; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Destroy; @@ -223,7 +222,7 @@ private static class DocumentStatisticLoader extends CacheLoader { private DocumentDAO getDocumentDAO() { - return (DocumentDAO) Component.getInstance(DocumentDAO.class); + return ServiceLocator.instance().getInstance(DocumentDAO.class); } @Override @@ -237,7 +236,7 @@ public WordStatistic load(DocumentLocaleKey key) throws Exception { private static class HTextFlowTargetIdLoader extends CacheLoader { DocumentDAO getDocumentDAO() { - return (DocumentDAO) Component.getInstance(DocumentDAO.class); + return ServiceLocator.instance().getInstance(DocumentDAO.class); } @Override @@ -286,7 +285,7 @@ private static DocumentStatus updateDocumentStatus(DocumentDAO documentDAO, @AllArgsConstructor @EqualsAndHashCode @Getter - public class DocumentLocaleKey implements Serializable { + public static final class DocumentLocaleKey implements Serializable { private Long documentId; private LocaleId localeId; } diff --git a/zanata-war/src/main/java/org/zanata/service/impl/EmailServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/EmailServiceImpl.java index 8bb3af0954..f1d7957dee 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/EmailServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/EmailServiceImpl.java @@ -23,34 +23,47 @@ import java.security.Principal; import java.util.ArrayList; import java.util.List; -import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.jboss.seam.ScopeType; +import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; -import org.jboss.seam.core.ResourceBundle; -import org.jboss.seam.faces.Renderer; import org.jboss.seam.security.RunAsOperation; import org.jboss.seam.security.management.IdentityManager; import org.zanata.ApplicationConfiguration; +import org.zanata.action.VersionGroupJoinAction; import org.zanata.dao.PersonDAO; +import org.zanata.email.ActivationEmailStrategy; +import org.zanata.email.Addresses; +import org.zanata.email.EmailBuilder; +import org.zanata.email.EmailStrategy; +import org.zanata.email.EmailValidationEmailStrategy; +import org.zanata.email.PasswordResetEmailStrategy; +import org.zanata.email.UsernameChangedEmailStrategy; +import org.zanata.i18n.Messages; +import org.zanata.model.HLocale; +import org.zanata.model.HLocaleMember; import org.zanata.model.HPerson; import org.zanata.service.EmailService; -import org.zanata.util.ZanataMessages; + +import javax.mail.internet.InternetAddress; + +import static org.zanata.email.Addresses.getAddresses; /** * @author Alex Eng aeng@redhat.com */ +@AutoCreate @Name("emailServiceImpl") @Scope(ScopeType.STATELESS) @Slf4j -// TODO refactor class to minimise duplicate code public class EmailServiceImpl implements EmailService { - @In(create = true) - private Renderer renderer; + + @In + private EmailBuilder emailBuilder; @In private IdentityManager identityManager; @@ -62,150 +75,133 @@ public class EmailServiceImpl implements EmailService { private ApplicationConfiguration applicationConfiguration; @In - private ZanataMessages zanataMessages; + private VersionGroupJoinAction versionGroupJoinAction; + + @In + private Messages msgs; + + /** + * + * @return the list of users with the admin role + */ + private List getAdmins() { + // required to read admin users for a non-admin session + final List admins = new ArrayList(); + new RunAsOperation() { + @Override + public void execute() { + for (Principal admin : identityManager.listMembers("admin")) { + admins.add(personDAO.findByUsername(admin.getName())); + } + } + }.addRole("admin").run(); - private String toName; - private String toEmailAddr; - private String receivedReason; - private String activationKey; + return admins; + } + + private List getCoordinators(HLocale locale) { + List coordinators = new ArrayList(); + + for (HLocaleMember member : locale.getMembers()) { + if (member.isCoordinator()) { + coordinators.add(member.getPerson()); + } + } + return coordinators; + } @Override - public String sendActivationEmail(String emailTemplate, String toName, + public String sendActivationEmail(String toName, String toEmailAddr, String activationKey) { - this.toName = toName; - this.toEmailAddr = toEmailAddr; - this.activationKey = activationKey; - renderer.render(emailTemplate); - - log.info( - "Sent activation account email: toName '{}', toEmailAddress '{}'", - toName, toEmailAddr); - return zanataMessages.getMessage("jsf.Account.ActivationMessage"); + InternetAddress to = Addresses.getAddress(toEmailAddr, toName); + emailBuilder.sendMessage(new ActivationEmailStrategy(activationKey), + null, to); + return msgs.get("jsf.Account.ActivationMessage"); } @Override - public String sendToLanguageCoordinators(String emailTemplate, - List coordinators, String fromName, String fromLoginName, - String replyEmail, String subject, String message, String language) { - if (!coordinators.isEmpty()) { - receivedReason = - zanataMessages.getMessage("jsf.email.coordinator.ReceivedReason"); - for (HPerson coord : coordinators) { - toName = coord.getName(); - toEmailAddr = coord.getEmail(); - renderer.render(emailTemplate); - } - log.info( - "Sent language team coordinator email: fromName '{}', fromLoginName '{}', replyEmail '{}', subject '{}', message '{}', language '{}'", - fromName, fromLoginName, replyEmail, subject, message, - language); - return zanataMessages.getMessage("jsf.email.coordinator.SentNotification"); - } else { - return sendToAdminEmails(emailTemplate, fromName, fromLoginName, - replyEmail, subject, message); - } + public String sendEmailValidationEmail(String toName, + String toEmailAddr, String activationKey) { + InternetAddress to = Addresses.getAddress(toEmailAddr, toName); + emailBuilder.sendMessage(new EmailValidationEmailStrategy(activationKey), + null, to); + return msgs.get("jsf.email.accountchange.SentNotification"); } @Override - public String sendToVersionGroupMaintainer(String emailTemplate, - List maintainers, String fromName, String fromLoginName, - String replyEmail, String subject, String message) { - if (!maintainers.isEmpty()) { - receivedReason = zanataMessages.getMessage("jsf.email.group.maintainer.ReceivedReason"); - for (HPerson maintainer : maintainers) { - toName = maintainer.getName(); - toEmailAddr = maintainer.getEmail(); - renderer.render(emailTemplate); - } - log.info( - "Sent version group maintainer email: fromName '{}', fromLoginName '1}', replyEmail '{}', subject '{}', message '{}'", - fromName, fromLoginName, replyEmail, subject, message); - return zanataMessages.getMessage("jsf.email.group.maintainer.SentNotification"); - } else { - return sendToAdminEmails(emailTemplate, fromName, fromLoginName, - replyEmail, subject, message); - } + public String sendPasswordResetEmail(HPerson person, String key) { + InternetAddress to = Addresses.getAddress(person); + emailBuilder.sendMessage(new PasswordResetEmailStrategy(key), null, to); + return msgs.get("jsf.email.passwordreset.SentNotification"); } @Override - public String sendToAdminEmails(String emailTemplate, String fromName, - String fromLoginName, String replyEmail, String subject, - String message) { + public String sendToAdmins(EmailStrategy strategy) { List adminEmails = applicationConfiguration.getAdminEmail(); if (!adminEmails.isEmpty()) { - receivedReason = zanataMessages.getMessage( - "jsf.email.admin.ReceivedReason"); - toName = - ResourceBundle.instance().getString( - "jsf.ZanataAdministrator"); - for (String email : adminEmails) { - toEmailAddr = email; - renderer.render(emailTemplate); - } - log.info( - "Sent server admin email: fromName '{}', fromLoginName '{}', replyEmail '{}', subject '{}', message '{}'", - fromName, fromLoginName, replyEmail, subject, message); - return zanataMessages.getMessage("jsf.email.admin.SentNotification"); + String receivedReason = msgs.get("jsf.email.admin.ReceivedReason"); + String toName = msgs.get("jsf.ZanataAdministrator"); + emailBuilder.sendMessage(strategy, receivedReason, + getAddresses(adminEmails, toName)); + return msgs.get("jsf.email.admin.SentNotification"); } else { - return sendToAdminUsers(emailTemplate, fromName, fromLoginName, - replyEmail, subject, message); + return sendToAdminUsers(strategy); } } /** * Emails admin users with given template * - * @param emailTemplate */ - private String sendToAdminUsers(String emailTemplate, String fromName, - String fromLoginName, String replyEmail, String subject, - String message) { - receivedReason = zanataMessages.getMessage( + private String sendToAdminUsers(EmailStrategy strategy) { + String receivedReason = msgs.get( "jsf.email.admin.user.ReceivedReason"); - for (HPerson admin : getAdmins()) { - toName = admin.getName(); - toEmailAddr = admin.getEmail(); - renderer.render(emailTemplate); - } - - log.info( - "Sent admin users email: fromName '{}', fromLoginName '{}', replyEmail '{}', subject '{}', message '{}'", - fromName, fromLoginName, replyEmail, subject, message); - return zanataMessages.getMessage("jsf.email.admin.SentNotification"); - } - - /** - * - * @return a list of admin users - */ - private List getAdmins() { - // required to read admin users for a non-admin session - final List admins = new ArrayList(); - new RunAsOperation() { - @Override - public void execute() { - for (Principal admin : identityManager.listMembers("admin")) { - admins.add(personDAO.findByUsername(admin.getName())); - } - } - }.addRole("admin").run(); - - return admins; + emailBuilder.sendMessage(strategy, receivedReason, + getAddresses(getAdmins())); + return msgs.get("jsf.email.admin.SentNotification"); } - public String getToName() { - return toName; + @Override + public String sendToLanguageCoordinators(HLocale locale, + EmailStrategy strategy) { + List coordinators = getCoordinators(locale); + if (!coordinators.isEmpty()) { + String receivedReason = msgs.format( + "jsf.email.coordinator.ReceivedReason", + locale.retrieveNativeName()); + + emailBuilder.sendMessage(strategy, receivedReason, + getAddresses(coordinators)); + return msgs.format("jsf.email.coordinator.SentNotification", + locale.retrieveNativeName()); + } else { + return sendToAdmins(strategy); + } } - public String getToEmailAddr() { - return toEmailAddr; + @Override + public String sendToVersionGroupMaintainers(List maintainers, + EmailStrategy strategy) { + if (!maintainers.isEmpty()) { + String receivedReason = msgs.format( + "jsf.email.group.maintainer.ReceivedReason", + versionGroupJoinAction.getGroupName()); + emailBuilder.sendMessage(strategy, receivedReason, + getAddresses(maintainers)); + return msgs.format("jsf.email.group.maintainer.SentNotification", + versionGroupJoinAction.getGroupName()); + } else { + return sendToAdmins(strategy); + } } - public String getReceivedReason() { - return receivedReason; + @Override + public String sendUsernameChangedEmail(String email, String newUsername) { + InternetAddress to = Addresses.getAddress(email, newUsername); + boolean resetPassword = applicationConfiguration.isInternalAuth(); + emailBuilder.sendMessage(new UsernameChangedEmailStrategy( + newUsername, resetPassword), null, to); + return msgs.get("jsf.email.usernamechange.SentNotification"); } - public String getActivationKey() { - return activationKey; - } } diff --git a/zanata-war/src/main/java/org/zanata/service/impl/LockManagerServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/LockManagerServiceImpl.java index 6f3d2e9ff0..74f8b1bbc3 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/LockManagerServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/LockManagerServiceImpl.java @@ -23,7 +23,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; @@ -33,6 +32,7 @@ import org.zanata.lock.LockNotAcquiredException; import org.zanata.model.HAccount; import org.zanata.service.LockManagerService; +import org.zanata.util.ServiceLocator; /** * Default implementation of the {@link LockManagerService} interface. Manages @@ -79,8 +79,8 @@ public void release(Lock l) { private String getCurrentUser() { HAccount user = - (HAccount) Component - .getInstance(JpaIdentityStore.AUTHENTICATED_USER); + ServiceLocator.instance().getInstance( + JpaIdentityStore.AUTHENTICATED_USER, HAccount.class); String newLocker = user != null ? user.getUsername() : "unknown"; return newLocker; } diff --git a/zanata-war/src/main/java/org/zanata/service/impl/TransMemoryMergeServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/TransMemoryMergeServiceImpl.java index 0adb4494e7..dfee285e06 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/TransMemoryMergeServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/TransMemoryMergeServiceImpl.java @@ -20,6 +20,7 @@ */ package org.zanata.service.impl; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -143,7 +144,7 @@ public List executeMerge( } if (updateRequests.isEmpty()) { - return Lists.newArrayList(); + return Collections.EMPTY_LIST; } if (Events.exists()) { diff --git a/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java index 74ee8f4871..e4e779e6dd 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java @@ -20,29 +20,9 @@ */ package org.zanata.service.impl; -import static org.jboss.seam.ScopeType.STATELESS; -import static org.zanata.common.DocumentType.GETTEXT_PORTABLE_OBJECT; -import static org.zanata.common.DocumentType.GETTEXT_PORTABLE_OBJECT_TEMPLATE; -import static org.zanata.common.DocumentType.HTML; -import static org.zanata.common.DocumentType.IDML; -import static org.zanata.common.DocumentType.OPEN_DOCUMENT_GRAPHICS; -import static org.zanata.common.DocumentType.OPEN_DOCUMENT_PRESENTATION; -import static org.zanata.common.DocumentType.OPEN_DOCUMENT_SPREADSHEET; -import static org.zanata.common.DocumentType.OPEN_DOCUMENT_TEXT; -import static org.zanata.common.DocumentType.PLAIN_TEXT; -import static org.zanata.common.DocumentType.XML_DOCUMENT_TYPE_DEFINITION; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - +import com.google.common.base.Optional; +import com.google.common.collect.MapMaker; import lombok.extern.slf4j.Slf4j; - import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; @@ -54,6 +34,7 @@ import org.zanata.adapter.OpenOfficeAdapter; import org.zanata.adapter.PlainTextAdapter; import org.zanata.adapter.po.PoReader2; +import org.zanata.adapter.SubtitleAdapter; import org.zanata.common.DocumentType; import org.zanata.common.LocaleId; import org.zanata.common.ProjectType; @@ -67,8 +48,27 @@ import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.service.TranslationFileService; -import com.google.common.base.Optional; -import com.google.common.collect.MapMaker; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static org.jboss.seam.ScopeType.STATELESS; +import static org.zanata.common.DocumentType.GETTEXT_PORTABLE_OBJECT; +import static org.zanata.common.DocumentType.GETTEXT_PORTABLE_OBJECT_TEMPLATE; +import static org.zanata.common.DocumentType.HTML; +import static org.zanata.common.DocumentType.IDML; +import static org.zanata.common.DocumentType.OPEN_DOCUMENT_GRAPHICS; +import static org.zanata.common.DocumentType.OPEN_DOCUMENT_PRESENTATION; +import static org.zanata.common.DocumentType.OPEN_DOCUMENT_SPREADSHEET; +import static org.zanata.common.DocumentType.OPEN_DOCUMENT_TEXT; +import static org.zanata.common.DocumentType.PLAIN_TEXT; +import static org.zanata.common.DocumentType.SUBTITLE; +import static org.zanata.common.DocumentType.XML_DOCUMENT_TYPE_DEFINITION; /** * Default implementation of the TranslationFileService interface. @@ -94,6 +94,7 @@ public class TranslationFileServiceImpl implements TranslationFileService { DOCTYPEMAP.put(XML_DOCUMENT_TYPE_DEFINITION, DTDAdapter.class); DOCTYPEMAP.put(IDML, IDMLAdapter.class); DOCTYPEMAP.put(HTML, HTMLAdapter.class); + DOCTYPEMAP.put(SUBTITLE, SubtitleAdapter.class); } private static Set SUPPORTED_EXTENSIONS = diff --git a/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java index f0a897ee98..babc1ac6ed 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/TranslationServiceImpl.java @@ -59,6 +59,7 @@ import org.zanata.events.DocumentUploadedEvent; import org.zanata.events.TextFlowTargetStateEvent; import org.zanata.exception.ZanataServiceException; +import org.zanata.i18n.Messages; import org.zanata.lock.Lock; import org.zanata.model.HAccount; import org.zanata.model.HDocument; @@ -80,7 +81,6 @@ import org.zanata.service.TranslationService; import org.zanata.service.ValidationService; import org.zanata.util.ShortString; -import org.zanata.util.ZanataMessages; import org.zanata.webtrans.shared.model.TransUnitId; import org.zanata.webtrans.shared.model.TransUnitUpdateInfo; import org.zanata.webtrans.shared.model.TransUnitUpdateRequest; @@ -138,7 +138,7 @@ public class TranslationServiceImpl implements TranslationService { private TranslationMergeServiceFactory translationMergeServiceFactory; @In - private ZanataMessages zanataMessages; + private Messages msgs; @In private ActivityService activityServiceImpl; @@ -543,8 +543,7 @@ private String validateTranslations(ContentState newState, sb.append(validationMessage).append("\n"); } message = - zanataMessages.getMessage( - "jsf.TranslationContainsError", + msgs.format("jsf.TranslationContainsError", ShortString.shorten(translations.get(0)), sb.toString()); } diff --git a/zanata-war/src/main/java/org/zanata/service/impl/VersionGroupServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/VersionGroupServiceImpl.java index 986df906f5..dbd0902a88 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/VersionGroupServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/VersionGroupServiceImpl.java @@ -20,6 +20,7 @@ */ package org.zanata.service.impl; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -164,7 +165,7 @@ public Set getGroupActiveLocales(String groupSlug) { if (group != null) { return group.getActiveLocales(); } - return Sets.newHashSet(); + return Collections.EMPTY_SET; } @Override diff --git a/zanata-war/src/main/java/org/zanata/service/impl/VersionManager.java b/zanata-war/src/main/java/org/zanata/service/impl/VersionManager.java index 4a5f26d888..834c27111c 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/VersionManager.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/VersionManager.java @@ -7,8 +7,7 @@ import org.jboss.seam.annotations.Scope; @Name("versionManager") -// Singleton with no state -@Scope(ScopeType.APPLICATION) +@Scope(ScopeType.STATELESS) @Slf4j public class VersionManager { diff --git a/zanata-war/src/main/java/org/zanata/service/impl/VersionStateCacheImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/VersionStateCacheImpl.java index 3041816375..ce24b51aaa 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/VersionStateCacheImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/VersionStateCacheImpl.java @@ -24,7 +24,6 @@ import net.sf.ehcache.CacheManager; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Destroy; @@ -131,8 +130,8 @@ private static class VersionStatisticLoader extends CacheLoader { ProjectIterationDAO getProjectIterationDAO() { - return (ProjectIterationDAO) Component - .getInstance(ProjectIterationDAO.class); + return ServiceLocator.instance().getInstance( + ProjectIterationDAO.class); } @Override diff --git a/zanata-war/src/main/java/org/zanata/servlet/FileUploadServlet.java b/zanata-war/src/main/java/org/zanata/servlet/FileUploadServlet.java index bea7505dd3..86acd79f12 100644 --- a/zanata-war/src/main/java/org/zanata/servlet/FileUploadServlet.java +++ b/zanata-war/src/main/java/org/zanata/servlet/FileUploadServlet.java @@ -37,10 +37,7 @@ import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.jboss.seam.Component; import org.jboss.seam.servlet.ContextualHttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.zanata.common.LocaleId; import org.zanata.common.MergeType; import org.zanata.exception.ZanataServiceException; @@ -51,6 +48,7 @@ import org.zanata.service.TranslationService; import org.zanata.service.impl.TranslationFileServiceImpl; import org.zanata.service.impl.TranslationServiceImpl; +import org.zanata.util.ServiceLocator; import org.zanata.webtrans.client.ui.FileUploadDialog; /** @@ -102,11 +100,11 @@ private void doWork(HttpServletRequest req, HttpServletResponse resp) // process only multipart requests if (ServletFileUpload.isMultipartContent(req)) { translationFileServiceImpl = - (TranslationFileService) Component - .getInstance(TranslationFileServiceImpl.class); + ServiceLocator.instance().getInstance( + TranslationFileServiceImpl.class); translationServiceImpl = - (TranslationService) Component - .getInstance(TranslationServiceImpl.class); + ServiceLocator.instance().getInstance( + TranslationServiceImpl.class); // Create a factory for disk-based file items FileItemFactory factory = new DiskFileItemFactory(); diff --git a/zanata-war/src/main/java/org/zanata/servlet/LeakListener.java b/zanata-war/src/main/java/org/zanata/servlet/LeakListener.java index 1f5f4c0ea7..b8e52698d8 100644 --- a/zanata-war/src/main/java/org/zanata/servlet/LeakListener.java +++ b/zanata-war/src/main/java/org/zanata/servlet/LeakListener.java @@ -21,19 +21,21 @@ package org.zanata.servlet; -import java.util.logging.Level; - -import lombok.extern.java.Log; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor; /** * @author Sean Flanigan sflaniga@redhat.com * */ -@Log public class LeakListener extends ClassLoaderLeakPreventor { + + private static final Logger log = LoggerFactory + .getLogger(ClassLoaderLeakPreventor.class); + protected void debug(String s) { - log.fine(s); + log.debug(s); } protected void info(String s) { @@ -41,19 +43,19 @@ protected void info(String s) { } protected void warn(String s) { - log.warning(s); + log.warn(s); } protected void warn(Throwable t) { - log.log(Level.WARNING, "", t); + log.warn("", t); } protected void error(String s) { - log.severe(s); + log.error(s); } protected void error(Throwable t) { - log.log(Level.SEVERE, "", t); + log.error("", t); } } diff --git a/zanata-war/src/main/java/org/zanata/servlet/MultiFileUploadServlet.java b/zanata-war/src/main/java/org/zanata/servlet/MultiFileUploadServlet.java new file mode 100644 index 0000000000..2bf8cad90e --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/servlet/MultiFileUploadServlet.java @@ -0,0 +1,408 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; + +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.Response; + +import com.google.common.base.Optional; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.hibernate.StaleStateException; +import org.hibernate.exception.ConstraintViolationException; +import org.jboss.seam.servlet.ContextualHttpServletRequest; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zanata.action.AuthenticatedAccountHome; +import org.zanata.file.GlobalDocumentId; +import org.zanata.file.SourceDocumentUpload; +import org.zanata.file.UserFileUploadTracker; +import org.zanata.rest.DocumentFileUploadForm; +import org.zanata.rest.dto.ChunkUploadResponse; +import org.zanata.service.TranslationFileService; +import org.zanata.service.impl.TranslationFileServiceImpl; +import org.zanata.util.ServiceLocator; + +import static com.google.common.base.Strings.emptyToNull; + +/** + * Endpoint for upload dialogs using multi-file upload forms. + * + * Use GET on the endpoint to check that upload is acceptable, including whether + * the user is signed in and whether they already have an upload in-progress + * in a separate tab. + */ +@Slf4j +public class MultiFileUploadServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + public void init(ServletConfig config) { + } + + /** + * Use GET to check the endpoint before doing a POST. + * + * This allows the browser to check that the upload is allowed before attempting an upload. + */ + @Override + protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { + new ContextualHttpServletRequest(request) { + @Override + public void process() throws Exception { + respondWithUploadAvailability(response); + } + }.run(); + } + + /** + * Indicate in response any errors that would prevent upload to this endpoint. + * + * @param response to respond with error or success JSON + */ + private void respondWithUploadAvailability(HttpServletResponse response) throws IOException { + Optional reason = getCannotUploadReason(); + String responseBody = reason.isPresent() + ? "{ \"error\": \"" + reason.get() + "\" }" + : "{ \"success\": \"ok to upload\" }"; + response.setContentType("application/json"); + PrintWriter writer = response.getWriter(); + writer.write(responseBody); + writer.close(); + } + + /** + * @return the reason that the user cannot upload at this time. Reason will + * be absent if the user is able to upload. + */ + private Optional getCannotUploadReason() { + Optional accountId = getAccountId(); + boolean loggedIn = accountId.isPresent(); + + if (loggedIn) { + UserFileUploadTracker tracker = ServiceLocator.instance().getInstance( + UserFileUploadTracker.class); + boolean alreadyUploading = tracker.isUserUploading(accountId.get()); + if (alreadyUploading) { + return Optional.of("already uploading"); + } + } else { + return Optional.of("not logged in"); + } + return Optional.absent(); + } + + private Optional getAccountId() { + AuthenticatedAccountHome accountHome = ServiceLocator.instance().getInstance( + AuthenticatedAccountHome.class); + return Optional.fromNullable((Long) accountHome.getId()); + } + + @Override + protected void doPost(final HttpServletRequest request, + final HttpServletResponse response) throws ServletException, + IOException { + new ContextualHttpServletRequest(request) { + @Override + public void process() throws Exception { + processPost(request, response); + } + }.run(); + } + + /** + * Ensure the request is a Multipart request. + * + * Initiates processing if the request is multipart, otherwise respond with + * an error. + */ + private void processPost(HttpServletRequest request, HttpServletResponse response) + throws IOException { + if (ServletFileUpload.isMultipartContent(request)) { + registerForUploadAndProcessMultipartPost(request, response); + } else { + log.error("File upload received non-multipart request"); + response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, + "Unsupported request type. File upload supports only multipart requests."); + } + } + + /** + * Ensure that upload is allowed at this time, then initiate processing of + * the upload request. + * + * This method is responsible for making sure that a user only has one active + * upload at a time. + */ + private void registerForUploadAndProcessMultipartPost(HttpServletRequest request, + HttpServletResponse response) throws IOException { + // TODO at this point the server will expect a response per-file. The simplistic error responses may not be handled well + + Optional accountId = getAccountId(); + + if (accountId.isPresent()) { + UserFileUploadTracker tracker = ServiceLocator.instance().getInstance( + UserFileUploadTracker.class); + boolean registeredForUpload = tracker.tryToRegisterUserForFileUpload(accountId.get()); + if (!registeredForUpload) { + log.error("User with id {} is already uploading something.", accountId.get()); + respondWithError(response, "already uploading"); + } else { + try { + processMultipartPost(request, response); + } finally { + tracker.deRegisterUserForFileUpload(accountId.get()); + } + } + } else { + log.error("User attempted upload when not logged in."); + respondWithError(response, "not logged in"); + } + } + + private void respondWithError(HttpServletResponse response, String error) throws IOException { + JSONObject responseObject = new JSONObject(); + try { + responseObject.put("error", "upload failed: " + error); + } catch (JSONException e) { + log.error("Error while generating JSON", e); + } + response.setContentType("application/json"); + PrintWriter writer = response.getWriter(); + writer.write(responseObject.toString()); + writer.close(); + } + + private void processMultipartPost(HttpServletRequest request, + HttpServletResponse response) throws IOException { + + FileUploadRequestHandler uploadRequestHandler = new FileUploadRequestHandler(request); + JSONArray filesJson; + try { + filesJson = uploadRequestHandler.process(); + } catch (FileUploadException e) { + respondWithError(response, "upload failed: " + e.getMessage()); + return; + } + respondWithFiles(response, filesJson); + } + + private void respondWithFiles(HttpServletResponse response, JSONArray filesJson) throws IOException { + JSONObject responseObject = new JSONObject(); + try { + responseObject.put("files", filesJson); + } catch (JSONException e) { + log.error("error adding files list to JSON", e); + } + String responseString = responseObject.toString(); + log.info("response string: " + responseString); + response.setContentType("application/json"); + PrintWriter writer = response.getWriter(); + writer.write(responseString); + writer.close(); + } + + private class FileUploadRequestHandler { + private final HttpServletRequest request; + + private String projectSlug; + private String versionSlug; + private String path = ""; + private String lang = "en-US"; + private String fileParams = ""; + + private SourceDocumentUpload sourceUploader; + private TranslationFileService translationFileServiceImpl; + + public FileUploadRequestHandler(HttpServletRequest request) { + this.request = request; + projectSlug = request.getParameter("p"); + versionSlug = request.getParameter("v"); + + sourceUploader = ServiceLocator.instance().getInstance(SourceDocumentUpload.class); + translationFileServiceImpl = ServiceLocator.instance().getInstance( + TranslationFileServiceImpl.class); + } + + public JSONArray process() throws FileUploadException { + // FIXME fail with error? + if (translationFileServiceImpl == null) { + log.error("translationFileServiceImpl is null"); + } + + List items = getRequestItems(); + JSONArray filesJson = processFilesFromItems(items); + + return filesJson; + } + + private List getRequestItems() throws FileUploadException { + List items;// Create a factory for disk-based file items + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload uploadHandler = new ServletFileUpload(factory); + items = uploadHandler.parseRequest(request); + return items; + } + + private JSONArray processFilesFromItems(List items) { + // parameters are required before processing files + recordParametersFromItems(items); + + JSONArray filesJson = new JSONArray(); + for (FileItem item : items) { + if (!item.isFormField()) { + JSONObject jsono = processFileItem(item); + filesJson.put(jsono); + } + } + return filesJson; + } + + /** + * Must be called before processing any file items. + * + * @param items all items from multipart request. + */ + private void recordParametersFromItems(List items) { + // Make sure params are available before processing files + for (FileItem item : items) { + if (item.isFormField()) { + String field = item.getFieldName(); + String value = item.getString(); + if (field.equals("filepath")) { + this.path = value; + } else if (field.equals("filelang")) { + this.lang = value; + } else if (field.equals("fileparams")) { + this.fileParams = value; + } + } + } + } + + /** + * Process upload of a single file item from a multipart request. + * + * @return JSON summary of outcome of the attempt. + */ + private JSONObject processFileItem(FileItem item) { + String docId = translationFileServiceImpl.generateDocId(path, item.getName()); + GlobalDocumentId id = new GlobalDocumentId(projectSlug, versionSlug, docId); + + Optional errorMessage; + Optional successMessage = Optional.absent(); + + Optional concurrentUploadError = Optional.of("failed: someone else is already uploading this file"); + + try { + DocumentFileUploadForm form = createUploadFormForItem(item); + Response response = sourceUploader.tryUploadSourceFileWithoutHash(id, form); + ChunkUploadResponse responseEntity = (ChunkUploadResponse) response.getEntity(); + errorMessage = optionalStringEmptyIsAbsent(responseEntity.getErrorMessage()); + successMessage = optionalStringEmptyIsAbsent(responseEntity.getSuccessMessage()); + } catch (IOException e) { + errorMessage = Optional.of("could not access file data"); + } catch (OptimisticLockException e) { + errorMessage = concurrentUploadError; + } catch (StaleStateException e) { + // this happens in the same circumstances as OptimisticLockException + // but is thrown because we are using hibernate directly rather than + // through JPA. + errorMessage = concurrentUploadError; + } catch (ConstraintViolationException e) { + errorMessage = concurrentUploadError; + } catch (PersistenceException e) { + errorMessage = Optional.of("Timed out: failed because the file took too long to process"); + } + + return createJSONInfo(item, docId, errorMessage, successMessage); + } + + /** + * Create JSON summary of outcome of an attempt to process an item. + */ + private JSONObject createJSONInfo(FileItem item, String docId, Optional error, Optional success) { + JSONObject jsono = new JSONObject(); + + try { + jsono.put("name", docId); + jsono.put("size", item.getSize()); + if (error.isPresent()) { + if (error.get().equals("Valid combination of username and api-key for this server were not included in the request.")) { + error = Optional.of("not logged in"); + } + jsono.put("error", error.get()); + } else { + if (success.isPresent()) { + jsono.put("message", success.get()); + } + // TODO could provide REST URL for this file +// jsono.put("url", "upload?getfile=" + item.getName()); + } + } catch (JSONException e) { + log.error("Error while generating JSON", e); + } + return jsono; + } + + /** + * Create the upload form required by sourceUploader for file upload. + * + * @throws IOException if the input stream cannot be opened for the file data. + */ + private DocumentFileUploadForm createUploadFormForItem(FileItem item) throws IOException { + DocumentFileUploadForm form = new DocumentFileUploadForm(); + form.setAdapterParams(fileParams); + form.setFirst(true); + form.setLast(true); + form.setSize(item.getSize()); + form.setFileType(translationFileServiceImpl.extractExtension(item.getName())); + form.setFileStream(item.getInputStream()); + return form; + } + + + /** + * @return absent if the given String is null or empty, otherwise an + * Option containing the given String. + */ + private Optional optionalStringEmptyIsAbsent(String value) { + return(Optional.fromNullable(emptyToNull(value))); + } + } +} diff --git a/zanata-war/src/main/java/org/zanata/ui/AbstractAutocomplete.java b/zanata-war/src/main/java/org/zanata/ui/AbstractAutocomplete.java index 08bcd80755..15f49e34c8 100644 --- a/zanata-war/src/main/java/org/zanata/ui/AbstractAutocomplete.java +++ b/zanata-war/src/main/java/org/zanata/ui/AbstractAutocomplete.java @@ -24,9 +24,9 @@ import java.util.List; -import org.jboss.seam.Component; +import org.zanata.i18n.Messages; import org.zanata.seam.scope.ConversationScopeMessages; -import org.zanata.util.ZanataMessages; +import org.zanata.util.ServiceLocator; import lombok.Getter; import lombok.Setter; @@ -36,8 +36,8 @@ */ public abstract class AbstractAutocomplete { - protected ZanataMessages zanataMessages = (ZanataMessages) Component - .getInstance(ZanataMessages.class); + protected Messages msgs = + ServiceLocator.instance().getInstance(Messages.class); protected ConversationScopeMessages conversationScopeMessages = ConversationScopeMessages.instance(); diff --git a/zanata-war/src/main/java/org/zanata/ui/AbstractListFilter.java b/zanata-war/src/main/java/org/zanata/ui/AbstractListFilter.java index 88975be673..562a0c48d1 100644 --- a/zanata-war/src/main/java/org/zanata/ui/AbstractListFilter.java +++ b/zanata-war/src/main/java/org/zanata/ui/AbstractListFilter.java @@ -36,7 +36,7 @@ public abstract class AbstractListFilter { @Getter @Setter - private int pageSize = 10; + private int pageSize = 100; @Getter @Setter diff --git a/zanata-war/src/main/java/org/zanata/ui/AbstractSortAction.java b/zanata-war/src/main/java/org/zanata/ui/AbstractSortAction.java index 564b5a6e04..c76ce1ddbf 100644 --- a/zanata-war/src/main/java/org/zanata/ui/AbstractSortAction.java +++ b/zanata-war/src/main/java/org/zanata/ui/AbstractSortAction.java @@ -55,6 +55,12 @@ public abstract class AbstractSortAction { protected DisplayUnit getDisplayUnit(SortingType.SortOption sortOption, WordStatistic statistic, Date date) { + + if (statistic.getTotal() == 0) { + return new DisplayUnit("stats--mini", getMessage("jsf.document.noContent.label"), + "", getMessage("jsf.document.noContent.title")); + } + DisplayUnit displayUnit; String displayString = null; diff --git a/zanata-war/src/main/java/org/zanata/ui/ActivityEntry.java b/zanata-war/src/main/java/org/zanata/ui/ActivityEntry.java index 5fb956b313..3c7d83ad34 100644 --- a/zanata-war/src/main/java/org/zanata/ui/ActivityEntry.java +++ b/zanata-war/src/main/java/org/zanata/ui/ActivityEntry.java @@ -27,7 +27,6 @@ import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; -import org.zanata.annotation.CachedMethodResult; import org.zanata.common.ActivityType; import org.zanata.dao.DocumentDAO; import org.zanata.model.Activity; diff --git a/zanata-war/src/main/java/org/zanata/ui/ProgressBar.java b/zanata-war/src/main/java/org/zanata/ui/ProgressBar.java index 6dc134b0fe..402258c39e 100644 --- a/zanata-war/src/main/java/org/zanata/ui/ProgressBar.java +++ b/zanata-war/src/main/java/org/zanata/ui/ProgressBar.java @@ -22,12 +22,16 @@ package org.zanata.ui; +import java.text.DecimalFormat; + /** * @author Alex Eng aeng@redhat.com */ public interface ProgressBar { + final DecimalFormat PERCENT_FORMAT = new DecimalFormat("###.####"); + boolean isInProgress(); - int getCompletedPercentage(); + String getCompletedPercentage(); } diff --git a/zanata-war/src/main/java/org/zanata/ui/autocomplete/LocaleAutocomplete.java b/zanata-war/src/main/java/org/zanata/ui/autocomplete/LocaleAutocomplete.java index 2e316f86f7..32ebdbf6cf 100644 --- a/zanata-war/src/main/java/org/zanata/ui/autocomplete/LocaleAutocomplete.java +++ b/zanata-war/src/main/java/org/zanata/ui/autocomplete/LocaleAutocomplete.java @@ -2,11 +2,7 @@ import java.util.Collection; import java.util.List; -import java.util.Set; -import javax.annotation.Nullable; - -import org.jboss.seam.Component; import org.zanata.model.HLocale; import org.zanata.service.LocaleService; import org.zanata.service.impl.LocaleServiceImpl; @@ -16,12 +12,13 @@ import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; +import org.zanata.util.ServiceLocator; /** * @author Alex Eng aeng@redhat.com */ public abstract class LocaleAutocomplete extends AbstractAutocomplete { - protected LocaleService localeServiceImpl = (LocaleService) Component + protected LocaleService localeServiceImpl = ServiceLocator.instance() .getInstance(LocaleServiceImpl.class); protected List supportedLocales = localeServiceImpl diff --git a/zanata-war/src/main/java/org/zanata/ui/autocomplete/MaintainerAutocomplete.java b/zanata-war/src/main/java/org/zanata/ui/autocomplete/MaintainerAutocomplete.java index 7f2913c543..c00c811db8 100644 --- a/zanata-war/src/main/java/org/zanata/ui/autocomplete/MaintainerAutocomplete.java +++ b/zanata-war/src/main/java/org/zanata/ui/autocomplete/MaintainerAutocomplete.java @@ -2,14 +2,11 @@ import java.util.List; -import org.apache.commons.lang.StringUtils; -import org.jboss.seam.Component; import org.zanata.dao.PersonDAO; import org.zanata.model.HPerson; -import org.zanata.seam.scope.ConversationScopeMessages; import org.zanata.ui.AbstractAutocomplete; import org.zanata.ui.FilterUtil; -import org.zanata.util.ZanataMessages; +import org.zanata.util.ServiceLocator; /** * @author Alex Eng aeng@redhat.com @@ -17,8 +14,8 @@ public abstract class MaintainerAutocomplete extends AbstractAutocomplete { - protected PersonDAO personDAO = (PersonDAO) Component - .getInstance(PersonDAO.class); + protected PersonDAO personDAO = ServiceLocator.instance().getInstance( + PersonDAO.class); protected abstract List getMaintainers(); diff --git a/zanata-war/src/main/java/org/zanata/ui/model/statistic/MessageStatistic.java b/zanata-war/src/main/java/org/zanata/ui/model/statistic/MessageStatistic.java index dd36ab96f2..41e335dfee 100644 --- a/zanata-war/src/main/java/org/zanata/ui/model/statistic/MessageStatistic.java +++ b/zanata-war/src/main/java/org/zanata/ui/model/statistic/MessageStatistic.java @@ -5,6 +5,8 @@ */ public class MessageStatistic extends AbstractStatistic { + private static final long serialVersionUID = 1L; + public MessageStatistic() { super(); } diff --git a/zanata-war/src/main/java/org/zanata/ui/model/statistic/WordStatistic.java b/zanata-war/src/main/java/org/zanata/ui/model/statistic/WordStatistic.java index 640883b551..ad99f8fa5f 100644 --- a/zanata-war/src/main/java/org/zanata/ui/model/statistic/WordStatistic.java +++ b/zanata-war/src/main/java/org/zanata/ui/model/statistic/WordStatistic.java @@ -8,6 +8,8 @@ */ public class WordStatistic extends AbstractStatistic { + private static final long serialVersionUID = -8807499518683834883L; + @Getter @Setter private double remainingHours; diff --git a/zanata-war/src/main/java/org/zanata/util/EmptyEnumeration.java b/zanata-war/src/main/java/org/zanata/util/EmptyEnumeration.java new file mode 100644 index 0000000000..ccfc141605 --- /dev/null +++ b/zanata-war/src/main/java/org/zanata/util/EmptyEnumeration.java @@ -0,0 +1,22 @@ +package org.zanata.util; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +public class EmptyEnumeration implements Enumeration { + private static final EmptyEnumeration INSTANCE + = new EmptyEnumeration(); + public static Enumeration instance() { + return (Enumeration) INSTANCE; + } + + @Override + public boolean hasMoreElements() { + return false; + } + + @Override + public E nextElement() { + throw new NoSuchElementException(); + } +} diff --git a/zanata-war/src/main/java/org/zanata/util/ServiceLocator.java b/zanata-war/src/main/java/org/zanata/util/ServiceLocator.java index 8c59f553b1..acc1c975e2 100644 --- a/zanata-war/src/main/java/org/zanata/util/ServiceLocator.java +++ b/zanata-war/src/main/java/org/zanata/util/ServiceLocator.java @@ -60,6 +60,10 @@ public T getInstance(String name, Class clazz) { return (T) Component.getInstance(name); } + public T getInstance(String name, ScopeType scope, Class clazz) { + return (T) Component.getInstance(name, scope); + } + public EntityManager getEntityManager() { return (EntityManager) Component.getInstance("entityManager"); } diff --git a/zanata-war/src/main/java/org/zanata/util/ZanataMessages.java b/zanata-war/src/main/java/org/zanata/util/ZanataMessages.java deleted file mode 100644 index 1df2c71c8b..0000000000 --- a/zanata-war/src/main/java/org/zanata/util/ZanataMessages.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010, Red Hat, Inc. and individual contributors as indicated by the - * @author tags. See the copyright.txt file in the distribution for a full - * listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this software; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF - * site: http://www.fsf.org. - */ -package org.zanata.util; - -import java.util.ResourceBundle; - -import org.jboss.seam.ScopeType; -import org.jboss.seam.annotations.AutoCreate; -import org.jboss.seam.annotations.In; -import org.jboss.seam.annotations.Name; -import org.jboss.seam.annotations.Scope; -import org.jboss.seam.core.Interpolator; - -/** - * Utility component to help with programmatic access to the message resource - * bundle. - * - * Contrary to the {@link org.jboss.seam.international.Messages} component, this - * component does not hold already interpolated messages, but rather allows - * interpolation to happen on demmand. Use this component when there is a need - * to access parametrized messages. - * - * @author Carlos Munoz camunoz@redhat.com - */ -@Name("zanataMessages") -@Scope(ScopeType.STATELESS) -@AutoCreate -public class ZanataMessages { - @In - private ResourceBundle resourceBundle; - - @In - private Interpolator interpolator; - - public String getMessage(String key, Object... args) { - String template = resourceBundle.getString(key); - return interpolator.interpolate(template, args); - } -} diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java index 005b834d73..342ce5ea54 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/AppPresenter.java @@ -57,7 +57,7 @@ import com.allen_sauer.gwt.log.client.Log; import com.google.common.base.Strings; import com.google.common.collect.Lists; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.inject.Inject; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/DocumentListPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/DocumentListPresenter.java index 533e0a6b9b..4981072e6d 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/DocumentListPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/DocumentListPresenter.java @@ -87,7 +87,7 @@ import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent; import com.google.inject.Inject; @@ -796,7 +796,7 @@ private int compareTranslated(DocumentNode o1, DocumentNode o2) { TranslationStatistics msgStats2 = o2.getDocInfo().getStats() .getStats(localeId.getId(), StatUnit.MESSAGE); - return (int) (msgStats1.getApproved() - msgStats2.getApproved()); + return (int) (msgStats1.getTranslatedAndApproved() - msgStats2.getTranslatedAndApproved()); } else { TranslationStatistics msgStats1 = o1.getDocInfo().getStats() @@ -804,7 +804,7 @@ private int compareTranslated(DocumentNode o1, DocumentNode o2) { TranslationStatistics msgStats2 = o2.getDocInfo().getStats() .getStats(localeId.getId(), StatUnit.WORD); - return (int) (msgStats1.getApproved() - msgStats2.getApproved()); + return (int) (msgStats1.getTranslatedAndApproved() - msgStats2.getTranslatedAndApproved()); } } @@ -822,17 +822,17 @@ private int compareUntranslated(DocumentNode o1, DocumentNode o2) { TranslationStatistics msgStats2 = o2.getDocInfo().getStats() .getStats(localeId.getId(), StatUnit.MESSAGE); - return (int) (msgStats1.getUntranslated() - msgStats2 - .getUntranslated()); + return (int) (msgStats1.getIncomplete() - msgStats2 + .getIncomplete()); } else { - TranslationStatistics msgStats1 = + TranslationStatistics wordStats1 = o1.getDocInfo().getStats() .getStats(localeId.getId(), StatUnit.WORD); - TranslationStatistics msgStats2 = + TranslationStatistics wordStats2 = o2.getDocInfo().getStats() .getStats(localeId.getId(), StatUnit.WORD); - return (int) (msgStats1.getUntranslated() - msgStats2 - .getUntranslated()); + return (int) (wordStats1.getIncomplete() - wordStats2 + .getIncomplete()); } } diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/GlossaryDetailsPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/GlossaryDetailsPresenter.java index c23e498506..2dce312d8f 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/GlossaryDetailsPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/GlossaryDetailsPresenter.java @@ -19,7 +19,7 @@ import com.allen_sauer.gwt.log.client.Log; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TargetContentsPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TargetContentsPresenter.java index 0141957ce7..f87215686a 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TargetContentsPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TargetContentsPresenter.java @@ -75,7 +75,7 @@ import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryDetailsPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryDetailsPresenter.java index 87272f7314..cf031bd802 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryDetailsPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryDetailsPresenter.java @@ -13,7 +13,7 @@ import org.zanata.webtrans.shared.rpc.GetTransMemoryDetailsAction; import org.zanata.webtrans.shared.rpc.TransMemoryDetailsList; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.inject.Inject; public class TransMemoryDetailsPresenter extends diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryPresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryPresenter.java index c8a629c882..28576528f5 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryPresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransMemoryPresenter.java @@ -30,7 +30,7 @@ import org.zanata.webtrans.shared.rpc.HasSearchType.SearchType; import com.allen_sauer.gwt.log.client.Log; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransUnitsTablePresenter.java b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransUnitsTablePresenter.java index 51011a3a23..60295d0563 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransUnitsTablePresenter.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/presenter/TransUnitsTablePresenter.java @@ -62,7 +62,7 @@ import com.allen_sauer.gwt.log.client.Log; import com.google.common.base.Objects; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.inject.Inject; import static org.zanata.webtrans.client.events.NotificationEvent.Severity.*; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/resources/Resources.java b/zanata-war/src/main/java/org/zanata/webtrans/client/resources/Resources.java index b5a516a644..e55f2b2735 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/resources/Resources.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/resources/Resources.java @@ -27,9 +27,6 @@ * Resources used by the entire application. */ public interface Resources extends ClientBundle { - @Source("images/crystal_project/_16x16/filesystems/file_doc.png") - ImageResource documentImage(); - @Source("images/loading.gif") ImageResource spinner(); diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/DelegatingDispatchAsync.java b/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/DelegatingDispatchAsync.java index 2baa377072..42ade9012f 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/DelegatingDispatchAsync.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/DelegatingDispatchAsync.java @@ -7,7 +7,7 @@ import org.zanata.webtrans.shared.auth.Identity; import org.zanata.webtrans.shared.model.UserWorkspaceContext; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; public class DelegatingDispatchAsync implements CachingDispatchAsync { diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/SeamDispatchAsync.java b/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/SeamDispatchAsync.java index 53d5dba61b..e7a05b99e8 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/SeamDispatchAsync.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/rpc/SeamDispatchAsync.java @@ -20,7 +20,7 @@ import org.zanata.webtrans.shared.rpc.WrappedAction; import com.allen_sauer.gwt.log.client.Log; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.user.client.Cookies; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.ServiceDefTarget; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Breadcrumb.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Breadcrumb.java index 2f3dfacc0f..546281b466 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Breadcrumb.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Breadcrumb.java @@ -4,7 +4,7 @@ package org.zanata.webtrans.client.ui; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.HasClickHandlers; import com.google.gwt.event.shared.HandlerRegistration; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorEditor.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorEditor.java index 28978cee7f..744bfd1ff1 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorEditor.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorEditor.java @@ -1,7 +1,7 @@ package org.zanata.webtrans.client.ui; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.NativeEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorReadOnlyWidget.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorReadOnlyWidget.java index db37417ac7..8e02147cf4 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorReadOnlyWidget.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/CodeMirrorReadOnlyWidget.java @@ -1,7 +1,7 @@ package org.zanata.webtrans.client.ui; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.TextAreaElement; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DialogBoxCloseButton.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DialogBoxCloseButton.java index 9b06f4a096..b84b8e0fa7 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DialogBoxCloseButton.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DialogBoxCloseButton.java @@ -2,7 +2,7 @@ import org.zanata.webtrans.client.resources.WebTransMessages; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.DialogBox; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DiffColorLegendPanel.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DiffColorLegendPanel.java index 2889ed86b5..d34d48011e 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DiffColorLegendPanel.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/DiffColorLegendPanel.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.keys.ShortcutContext; import org.zanata.webtrans.client.resources.WebTransMessages; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Editor.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Editor.java index 5485c53f30..b967768d90 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Editor.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Editor.java @@ -12,7 +12,7 @@ import com.allen_sauer.gwt.log.client.Log; import com.google.common.base.Objects; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.FocusEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/EditorButtonsWidget.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/EditorButtonsWidget.java index 2e705c8739..2ca9bde29f 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/EditorButtonsWidget.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/EditorButtonsWidget.java @@ -2,7 +2,7 @@ import org.zanata.webtrans.client.view.TargetContentsDisplay; import org.zanata.webtrans.shared.model.TransUnitId; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/HistoryEntryComparisonPanel.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/HistoryEntryComparisonPanel.java index 9728ab322c..51b13d1825 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/HistoryEntryComparisonPanel.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/HistoryEntryComparisonPanel.java @@ -4,7 +4,7 @@ import org.zanata.webtrans.client.resources.WebTransMessages; import org.zanata.webtrans.shared.model.TransHistoryItem; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationDetailsBox.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationDetailsBox.java index 4058066e34..91ca62427d 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationDetailsBox.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationDetailsBox.java @@ -8,7 +8,7 @@ import org.zanata.webtrans.client.util.DateUtil; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationItem.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationItem.java index a11853b809..b20ff3d6e0 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationItem.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/NotificationItem.java @@ -26,7 +26,7 @@ import org.zanata.webtrans.client.resources.WebTransMessages; import org.zanata.webtrans.client.util.DateUtil; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.resources.client.CssResource; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Pager.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Pager.java index 6ceb49e297..81d19544b1 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Pager.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/Pager.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.resources.WebTransMessages; import com.allen_sauer.gwt.log.client.Log; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReferencePanel.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReferencePanel.java index bb7c2d1753..64f2dd1234 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReferencePanel.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReferencePanel.java @@ -1,6 +1,6 @@ package org.zanata.webtrans.client.ui; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentInputWidget.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentInputWidget.java index 4f8ef268fd..d0aca7c1b9 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentInputWidget.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentInputWidget.java @@ -22,7 +22,7 @@ package org.zanata.webtrans.client.ui; import org.zanata.webtrans.client.view.ForceReviewCommentDisplay; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentItemLine.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentItemLine.java index f3baf2c39c..5749c036f2 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentItemLine.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ReviewCommentItemLine.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.util.DateUtil; import org.zanata.webtrans.shared.model.ReviewComment; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchField.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchField.java index e47fd34afc..163ec8fb6d 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchField.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchField.java @@ -20,7 +20,7 @@ */ package org.zanata.webtrans.client.ui; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.FocusEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java index 31b941c664..0894905734 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SearchResultsDocumentTable.java @@ -36,7 +36,7 @@ import com.google.gwt.cell.client.Cell.Context; import com.google.gwt.cell.client.CheckboxCell; import com.google.gwt.cell.client.ValueUpdater; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style.Unit; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SourcePanel.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SourcePanel.java index 818d32fdc7..62fafd5659 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SourcePanel.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/SourcePanel.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.resources.NavigationMessages; import org.zanata.webtrans.shared.model.TransUnitId; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Document; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TMMergeForm.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TMMergeForm.java index ebe4ca436b..eed5d07b5d 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TMMergeForm.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TMMergeForm.java @@ -28,7 +28,7 @@ import org.zanata.webtrans.shared.rpc.MergeOptions; import com.google.common.base.Preconditions; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.CssResource; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TooltipPopupPanel.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TooltipPopupPanel.java index 3ef95d461d..386d9a7fcd 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TooltipPopupPanel.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TooltipPopupPanel.java @@ -20,7 +20,7 @@ */ package org.zanata.webtrans.client.ui; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.i18n.client.LocaleInfo; import com.google.gwt.resources.client.CssResource; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransHistoryItemLine.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransHistoryItemLine.java index 5fa76ca9c3..ac99cfee5e 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransHistoryItemLine.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransHistoryItemLine.java @@ -25,7 +25,7 @@ import org.zanata.webtrans.client.resources.WebTransMessages; import org.zanata.webtrans.client.util.DateUtil; import org.zanata.webtrans.shared.model.TransHistoryItem; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.SpanElement; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.safehtml.client.SafeHtmlTemplates; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransMemoryMergePopupPanelView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransMemoryMergePopupPanelView.java index 590f865a0a..08fde7cc6b 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransMemoryMergePopupPanelView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransMemoryMergePopupPanelView.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.resources.UiMessages; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.user.client.ui.DialogBox; import com.google.gwt.user.client.ui.Label; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitCountBar.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitCountBar.java index 472571d21e..b32a4bdeac 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitCountBar.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitCountBar.java @@ -8,7 +8,7 @@ import org.zanata.webtrans.client.util.TextFormatUtil; import org.zanata.webtrans.shared.model.UserWorkspaceContext; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitDetailsPanel.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitDetailsPanel.java index f4a9d10774..a3934f376f 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitDetailsPanel.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TransUnitDetailsPanel.java @@ -5,7 +5,7 @@ import org.zanata.webtrans.shared.model.TransUnit; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslationHistoryView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslationHistoryView.java index 7b34610d87..dbb9b13d29 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslationHistoryView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslationHistoryView.java @@ -9,7 +9,7 @@ import org.zanata.webtrans.shared.model.ReviewComment; import org.zanata.webtrans.shared.model.TransHistoryItem; import com.google.common.collect.Lists; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslatorListWidget.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslatorListWidget.java index d8f048b764..8da00774d3 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslatorListWidget.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/TranslatorListWidget.java @@ -1,6 +1,6 @@ package org.zanata.webtrans.client.ui; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationMessagePanelView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationMessagePanelView.java index 9e31998c96..f4f9db8a97 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationMessagePanelView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationMessagePanelView.java @@ -26,7 +26,7 @@ import com.allen_sauer.gwt.log.client.Log; import com.google.common.collect.Maps; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.CssResource; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationWarningPanel.java b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationWarningPanel.java index 99868626e9..42df43e11e 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationWarningPanel.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/ui/ValidationWarningPanel.java @@ -37,7 +37,7 @@ import org.zanata.webtrans.shared.model.TransUnitId; import org.zanata.webtrans.shared.model.ValidationAction; import com.google.common.collect.Lists; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/AppView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/AppView.java index bacef6f71e..7dfadd8c6c 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/AppView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/AppView.java @@ -36,7 +36,7 @@ import org.zanata.webtrans.client.ui.UnorderedListWidget; import org.zanata.webtrans.shared.model.UserWorkspaceContext; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.UListElement; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/AttentionKeyShortcutView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/AttentionKeyShortcutView.java index b184cf0001..1e78d4755b 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/AttentionKeyShortcutView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/AttentionKeyShortcutView.java @@ -1,7 +1,7 @@ package org.zanata.webtrans.client.view; import org.zanata.webtrans.client.resources.WebTransMessages; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/ChangeReferenceLangView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/ChangeReferenceLangView.java index 39321857c6..66d2d1290c 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/ChangeReferenceLangView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/ChangeReferenceLangView.java @@ -20,7 +20,7 @@ */ package org.zanata.webtrans.client.view; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.resources.client.CssResource; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListOptionsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListOptionsView.java index 82a8a53cd8..03e2e65ae1 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListOptionsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListOptionsView.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.presenter.UserConfigHolder; import org.zanata.webtrans.client.resources.WebTransMessages; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java index fd0a712225..5e6a486156 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java @@ -43,7 +43,7 @@ import org.zanata.webtrans.shared.model.UserWorkspaceContext; import org.zanata.webtrans.shared.model.WorkspaceId; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/EditorOptionsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/EditorOptionsView.java index eabb4b83fb..34b9cd9f62 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/EditorOptionsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/EditorOptionsView.java @@ -30,7 +30,7 @@ import org.zanata.webtrans.shared.model.DiffMode; import org.zanata.webtrans.shared.rpc.NavOption; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryDetailsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryDetailsView.java index 28fe6cbd7b..c51720bcf4 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryDetailsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryDetailsView.java @@ -9,7 +9,7 @@ import org.zanata.webtrans.client.util.DateUtil; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryView.java index 4242beee91..024520f69a 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/GlossaryView.java @@ -10,7 +10,7 @@ import org.zanata.webtrans.shared.model.GlossaryResultItem; import org.zanata.webtrans.shared.rpc.HasSearchType.SearchType; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java index 16361b70fb..7ccf65789e 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/KeyShortcutView.java @@ -29,7 +29,7 @@ import com.google.common.base.Strings; import com.google.gwt.cell.client.SafeHtmlCell; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.resources.client.CssResource; import com.google.gwt.safehtml.shared.SafeHtml; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/NotificationView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/NotificationView.java index d474571a2c..45ccdbda4a 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/NotificationView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/NotificationView.java @@ -29,7 +29,7 @@ import org.zanata.webtrans.client.ui.NotificationItem; import org.zanata.webtrans.client.ui.UnorderedListWidget; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/OptionsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/OptionsView.java index fdb0d6820b..90a490cee0 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/OptionsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/OptionsView.java @@ -22,7 +22,7 @@ import org.zanata.webtrans.shared.rpc.ThemesOption; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java index 0bc86c6f84..590456b95e 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/SearchResultsView.java @@ -30,7 +30,7 @@ import org.zanata.webtrans.client.ui.SearchResultsDocumentTable; import com.google.gwt.cell.client.ActionCell.Delegate; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.HasChangeHandlers; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/SideMenuView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/SideMenuView.java index f7c9879758..e50e1ce264 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/SideMenuView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/SideMenuView.java @@ -3,7 +3,7 @@ import org.zanata.webtrans.client.events.NotificationEvent.Severity; import org.zanata.webtrans.client.resources.WebTransMessages; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TargetContentsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TargetContentsView.java index 1afd58a0a2..1a76a7a6f2 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TargetContentsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TargetContentsView.java @@ -40,7 +40,7 @@ import com.google.common.base.Objects; import com.google.common.collect.Lists; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransFilterView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransFilterView.java index cb15f56f83..b8f1e121c6 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransFilterView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransFilterView.java @@ -24,7 +24,7 @@ import org.zanata.webtrans.client.resources.UiMessages; import org.zanata.webtrans.client.ui.EditorSearchField; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryDetailsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryDetailsView.java index 02bbcaef27..7ed7c7404a 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryDetailsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryDetailsView.java @@ -10,7 +10,7 @@ import org.zanata.webtrans.client.util.DateUtil; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.safehtml.shared.SafeHtml; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryView.java index dfbe964449..05503400aa 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransMemoryView.java @@ -16,9 +16,8 @@ import org.zanata.webtrans.shared.rpc.HasSearchType.SearchType; import com.google.common.base.Joiner; -import com.google.common.base.Splitter; import com.google.common.collect.Lists; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; @@ -326,11 +325,7 @@ public void onClick(ClickEvent event) { Anchor infoCell = new Anchor(); if (item.getMatchType() == MatchType.Imported) { String originStr = Joiner.on(", ").join(item.getOrigins()); - String ellipsizedStr = - Splitter.fixedLength(10).limit(2).split(originStr) - .iterator().next() - + "..."; - infoCell.setText(ellipsizedStr); + infoCell.setText(shorten(originStr, 10)); infoCell.setTitle(originStr); } else { infoCell.setStyleName("icon-info-circle-2 txt--lead"); @@ -348,6 +343,15 @@ public void onClick(ClickEvent event) { } } + // TODO: Replace with ShortString::shorten when gwt can resolve the module + private String shorten(String s, int maxLength) { + String ellipsis = "…"; + if (s.length() <= maxLength) { + return s; + } + return s.substring(0, maxLength - ellipsis.length()) + ellipsis; + } + private static boolean odd(int n) { return n % 2 != 0; } diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitNavigationView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitNavigationView.java index 9090c98914..366061f3c0 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitNavigationView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitNavigationView.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.resources.NavigationMessages; import org.zanata.webtrans.shared.rpc.NavOption; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitsTableView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitsTableView.java index 42371de375..39f3e6df56 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitsTableView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TransUnitsTableView.java @@ -6,7 +6,7 @@ import org.zanata.webtrans.client.ui.FilterViewConfirmationDisplay; import org.zanata.webtrans.client.ui.LoadingPanel; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.ResizeEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationEditorView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationEditorView.java index 24a1e13e79..fd1c1e5905 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationEditorView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationEditorView.java @@ -24,7 +24,7 @@ import org.zanata.webtrans.client.ui.HasPager; import org.zanata.webtrans.client.ui.Pager; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.FocusEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationView.java index 8a5357a400..e37d4eecd6 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/TranslationView.java @@ -23,7 +23,7 @@ import org.zanata.webtrans.client.presenter.TranslationPresenter; import org.zanata.webtrans.client.ui.SplitLayoutPanelHelper; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/ValidationOptionsView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/ValidationOptionsView.java index ec897a09d7..d19cfeb796 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/ValidationOptionsView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/ValidationOptionsView.java @@ -9,7 +9,7 @@ import org.zanata.webtrans.client.ui.UnorderedListWidget; import org.zanata.webtrans.client.util.DateUtil; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.uibinder.client.UiBinder; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/WorkspaceUsersView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/WorkspaceUsersView.java index d1806e580c..de2d253d22 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/WorkspaceUsersView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/WorkspaceUsersView.java @@ -8,7 +8,7 @@ import org.zanata.webtrans.shared.rpc.HasWorkspaceChatData.MESSAGE_TYPE; import com.google.common.base.Strings; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.FocusEvent; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/HibernateIntegrator.java b/zanata-war/src/main/java/org/zanata/webtrans/server/HibernateIntegrator.java index 3468a47865..cb0c994ddb 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/HibernateIntegrator.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/HibernateIntegrator.java @@ -4,13 +4,12 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; -import org.hibernate.event.spi.PostUpdateEventListener; import org.hibernate.integrator.spi.Integrator; import org.hibernate.metamodel.source.MetadataImplementor; import org.hibernate.service.spi.SessionFactoryServiceRegistry; -import org.jboss.seam.Component; import org.jboss.seam.contexts.Contexts; import lombok.extern.slf4j.Slf4j; +import org.zanata.util.ServiceLocator; /** * Hibernate SPI. Register event listener for entity lifecycle events. @@ -28,8 +27,8 @@ public void integrate(Configuration configuration, final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class); TranslationUpdateListener updateListener = - (TranslationUpdateListener) Component - .getInstance(TranslationUpdateListener.class); + ServiceLocator.instance().getInstance( + TranslationUpdateListener.class); log.info("register event listener: {}", updateListener); // We have to use POST_UPDATE not POST_UPDATE_COMMIT. Because we // still need to access some other entities to make transunit. After diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/SeamDispatch.java b/zanata-war/src/main/java/org/zanata/webtrans/server/SeamDispatch.java index e79ab33e73..a9392c1094 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/SeamDispatch.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/SeamDispatch.java @@ -16,7 +16,6 @@ import net.customware.gwt.dispatch.shared.Result; import net.customware.gwt.dispatch.shared.UnsupportedActionException; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; @@ -26,6 +25,7 @@ import org.jboss.seam.security.AuthorizationException; import org.jboss.seam.security.NotLoggedInException; import org.jboss.seam.web.ServletContexts; +import org.zanata.util.ServiceLocator; import org.zanata.webtrans.shared.auth.AuthenticationError; import org.zanata.webtrans.shared.auth.AuthorizationError; import org.zanata.webtrans.shared.auth.InvalidTokenError; @@ -164,7 +164,7 @@ private , R extends Result> R doExecute(A action, Class handlerClazz = handlers.get(action.getClass()); final ActionHandler handler = - (ActionHandler) Component.getInstance(handlerClazz); + ServiceLocator.instance().getInstance(handlerClazz); if (handler == null) throw new UnsupportedActionException(action); diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationUpdateListener.java b/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationUpdateListener.java index af1bfb346a..8461ae6180 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationUpdateListener.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationUpdateListener.java @@ -6,7 +6,6 @@ import org.hibernate.event.spi.PostInsertEventListener; import org.hibernate.event.spi.PostUpdateEvent; import org.hibernate.event.spi.PostUpdateEventListener; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationWorkspaceManagerImpl.java b/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationWorkspaceManagerImpl.java index 5f148f8c8f..d609a51331 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationWorkspaceManagerImpl.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/TranslationWorkspaceManagerImpl.java @@ -9,7 +9,6 @@ import lombok.extern.slf4j.Slf4j; -import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Destroy; import org.jboss.seam.annotations.Name; @@ -33,6 +32,7 @@ import org.zanata.service.GravatarService; import org.zanata.service.LocaleService; import org.zanata.service.ValidationService; +import org.zanata.util.ServiceLocator; import org.zanata.webtrans.shared.NoSuchWorkspaceException; import org.zanata.webtrans.shared.auth.EditorClientId; import org.zanata.webtrans.shared.model.Person; @@ -82,26 +82,39 @@ public TranslationWorkspaceManagerImpl() { EventRegistryFactory.getInstance().getEventRegistry(); } + // TODO Requesting component by name for testability. This should be fixed + // in subsequent versions of AutoWire AccountDAO getAccountDAO() { - return (AccountDAO) Component.getInstance("accountDAO"); + return ServiceLocator.instance().getInstance("accountDAO", + AccountDAO.class); } + // TODO Requesting component by name for testability. This should be fixed + // in subsequent versions of AutoWire GravatarService getGravatarService() { - return (GravatarService) Component.getInstance("gravatarServiceImpl"); + return ServiceLocator.instance().getInstance("gravatarServiceImpl", + GravatarService.class); } + // TODO Requesting component by name for testability. This should be fixed + // in subsequent versions of AutoWire ProjectIterationDAO getProjectIterationDAO() { - return (ProjectIterationDAO) Component - .getInstance("projectIterationDAO"); + return ServiceLocator.instance().getInstance("projectIterationDAO", + ProjectIterationDAO.class); } + // TODO Requesting component by name for testability. This should be fixed + // in subsequent versions of AutoWire LocaleService getLocaleService() { - return (LocaleService) Component.getInstance("localeServiceImpl"); + return ServiceLocator.instance().getInstance("localeServiceImpl", + LocaleService.class); } + // TODO Requesting component by name for testability. This should be fixed + // in subsequent versions of AutoWire ValidationService getValidationService() { - return (ValidationService) Component - .getInstance("validationServiceImpl"); + return ServiceLocator.instance().getInstance("validationServiceImpl", + ValidationService.class); } @Observer(ZanataInit.EVENT_Zanata_Startup) diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java index 036b30058e..34a411b7cd 100755 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java @@ -170,16 +170,16 @@ private List getTextFlows(GetTransUnitList action, // TODO debt: this should use a left join to fetch target (and // possibly comments) textFlows = - textFlowDAO.getTextFlowsByDocumentId( - action.getDocumentId(), offset, + textFlowDAO.getTextFlowsByDocumentId(action + .getDocumentId().getId(), offset, action.getCount()); } else { // TODO debt: this is not scalable. But we may not have other // choice // for validation filter. Maybe use scrollable result will help? textFlows = - textFlowDAO.getAllTextFlowsByDocumentId(action - .getDocumentId()); + textFlowDAO.getTextFlowsByDocumentId(action + .getDocumentId().getId(), null, null); textFlows = validationServiceImpl.filterHasWarningOrErrorTextFlow( textFlows, action.getValidationIds(), diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/TransUnitUpdateHelper.java b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/TransUnitUpdateHelper.java index c1ff100ba9..7372b25875 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/TransUnitUpdateHelper.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/TransUnitUpdateHelper.java @@ -101,7 +101,8 @@ public UpdateTransUnitResult generateUpdateTransUnitResult( } private static TransUnitTransformer getTransUnitTransformer() { - return (TransUnitTransformer) Component.getInstance(TransUnitTransformer.class); + return ServiceLocator.instance() + .getInstance(TransUnitTransformer.class); } private static TransUnitUpdateInfo build( diff --git a/zanata-war/src/main/resources/ValidationMessages.properties b/zanata-war/src/main/resources/ValidationMessages.properties index 522257c0eb..708feaae38 100644 --- a/zanata-war/src/main/resources/ValidationMessages.properties +++ b/zanata-war/src/main/resources/ValidationMessages.properties @@ -10,7 +10,7 @@ javax.validation.constraints.Pattern.message=must match {regexp} javax.validation.constraints.Range.message=must be between {min} and {max} javax.validation.constraints.Size.message=size must be between {min} and {max} javax.validation.constraints.Email.message=must be a well-formed email address -javax.validation.constraints.Slug.message=must start and end with letter or number, and contain only letters, numbers, underscores and hyphens. +javax.validation.constraints.Slug.message=must start and end with letter or number, and contain only letters, numbers, periods, underscores and hyphens. javax.validation.constraints.Url.message=must be a valid URL #javax.validation.constraints.UrlNoSlash.message=must be a valid URL (without final slash) javax.validation.constraints.NotDuplicateEmail.message=duplicate email diff --git a/zanata-war/src/main/resources/ehcache.xml b/zanata-war/src/main/resources/ehcache.xml index 6993035200..078765f5e1 100644 --- a/zanata-war/src/main/resources/ehcache.xml +++ b/zanata-war/src/main/resources/ehcache.xml @@ -2,6 +2,8 @@ xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false"> + + - - diff --git a/zanata-war/src/main/resources/images/combo_box_arrow.png b/zanata-war/src/main/resources/images/combo_box_arrow.png deleted file mode 100644 index 824999ab2b..0000000000 Binary files a/zanata-war/src/main/resources/images/combo_box_arrow.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/actions/admin_icon.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/actions/admin_icon.png deleted file mode 100644 index ab94e87a0d..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/actions/admin_icon.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/actions/help.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/actions/help.png deleted file mode 100644 index 9f0c92f233..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/actions/help.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/bug.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/bug.png deleted file mode 100644 index 5fc4b25caf..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/bug.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/error.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/error.png deleted file mode 100755 index b5b93b7518..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/error.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/kdf.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/kdf.png deleted file mode 100644 index 7de3f48b15..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/kdf.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/kllckety.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/kllckety.png deleted file mode 100644 index 5f34ab07d7..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/kllckety.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/locale.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/locale.png deleted file mode 100644 index 291b52e8aa..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/locale.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/package_editors.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/package_editors.png deleted file mode 100644 index bbc2320a45..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/apps/package_editors.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_16x16/filesystems/file_doc.png b/zanata-war/src/main/resources/images/crystal_project/_16x16/filesystems/file_doc.png deleted file mode 100755 index 43ec054ac2..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_16x16/filesystems/file_doc.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/crystal_project/_48x48/apps/package_editors.png b/zanata-war/src/main/resources/images/crystal_project/_48x48/apps/package_editors.png deleted file mode 100644 index 22c39a9f25..0000000000 Binary files a/zanata-war/src/main/resources/images/crystal_project/_48x48/apps/package_editors.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/favicon.ico b/zanata-war/src/main/resources/images/favicon.ico deleted file mode 100644 index 3cc17b49cd..0000000000 Binary files a/zanata-war/src/main/resources/images/favicon.ico and /dev/null differ diff --git a/zanata-war/src/main/resources/images/first_entry.png b/zanata-war/src/main/resources/images/first_entry.png deleted file mode 100644 index a372ea0d31..0000000000 Binary files a/zanata-war/src/main/resources/images/first_entry.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/last_entry.png b/zanata-war/src/main/resources/images/last_entry.png deleted file mode 100644 index c712df36f3..0000000000 Binary files a/zanata-war/src/main/resources/images/last_entry.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/logo-small.png b/zanata-war/src/main/resources/images/logo-small.png deleted file mode 100644 index 11ca2d59e3..0000000000 Binary files a/zanata-war/src/main/resources/images/logo-small.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/logo.png b/zanata-war/src/main/resources/images/logo.png deleted file mode 100644 index bd9d26d303..0000000000 Binary files a/zanata-war/src/main/resources/images/logo.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/next_entry.png b/zanata-war/src/main/resources/images/next_entry.png deleted file mode 100644 index a41b216d23..0000000000 Binary files a/zanata-war/src/main/resources/images/next_entry.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/next_mode.png b/zanata-war/src/main/resources/images/next_mode.png deleted file mode 100644 index d14c772dcc..0000000000 Binary files a/zanata-war/src/main/resources/images/next_mode.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/openid/fedora.png b/zanata-war/src/main/resources/images/openid/fedora.png deleted file mode 100644 index dcf4518184..0000000000 Binary files a/zanata-war/src/main/resources/images/openid/fedora.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/openid/google.png b/zanata-war/src/main/resources/images/openid/google.png deleted file mode 100644 index 71f3a774f1..0000000000 Binary files a/zanata-war/src/main/resources/images/openid/google.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/openid/openid.png b/zanata-war/src/main/resources/images/openid/openid.png deleted file mode 100644 index 34a8e1be79..0000000000 Binary files a/zanata-war/src/main/resources/images/openid/openid.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/openid/yahoo.png b/zanata-war/src/main/resources/images/openid/yahoo.png deleted file mode 100644 index 7a268ea8b4..0000000000 Binary files a/zanata-war/src/main/resources/images/openid/yahoo.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/prev_entry.png b/zanata-war/src/main/resources/images/prev_entry.png deleted file mode 100644 index ec9fc10160..0000000000 Binary files a/zanata-war/src/main/resources/images/prev_entry.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/prev_mode.png b/zanata-war/src/main/resources/images/prev_mode.png deleted file mode 100644 index ce2301d22b..0000000000 Binary files a/zanata-war/src/main/resources/images/prev_mode.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/z-logo-16px.png b/zanata-war/src/main/resources/images/z-logo-16px.png deleted file mode 100644 index 3cc17b49cd..0000000000 Binary files a/zanata-war/src/main/resources/images/z-logo-16px.png and /dev/null differ diff --git a/zanata-war/src/main/resources/images/z-logo-50px.png b/zanata-war/src/main/resources/images/z-logo-50px.png deleted file mode 100644 index 05aa6047fa..0000000000 Binary files a/zanata-war/src/main/resources/images/z-logo-50px.png and /dev/null differ diff --git a/zanata-war/src/main/resources/messages.properties b/zanata-war/src/main/resources/messages.properties index 1eb81465e8..fc04fc8648 100644 --- a/zanata-war/src/main/resources/messages.properties +++ b/zanata-war/src/main/resources/messages.properties @@ -17,11 +17,11 @@ jsf.AnotherUserChangedTheSameDataPleaseTryAgain=Another user changed the same da jsf.YouDoNotHavePermissionToAccessThisResource=You do not have permission to access this resource. jsf.YourSessionHasTimedOutPleaseTryAgain=Your session has timed out. Please try again. jsf.UnexpectedError=An unexpected error has occurred. Please report this problem with details of what you were attempting. -jsf.ReportProblemInstructions=To report a problem, please use the '#{messages['jsf.ReportAProblem']}' link, available in the footer below. jsf.Actions=Actions jsf.Add=Add jsf.Cancel=Cancel +jsf.Done=Done jsf.CreateGroup=Create group jsf.Close=Close jsf.Clear=Clear @@ -42,7 +42,7 @@ jsf.projectType=Project Type jsf.project.projectType.Description=Help: Creating a project and project type jsf.iteration.projectType.Description=Help: Creating a version and project type jsf.projectType.NotSpecifiedBehaviour=If no project type is specified, the type from containing project is used. -jsf.projectType.detail.File=For plain text, Libre Office, InDesign etc. +jsf.projectType.detail.File=For plain text, Libre Office, InDesign, HTML, Subtitles etc. jsf.projectType.detail.Gettext=For gettext software strings. jsf.projectType.detail.Podir=For publican/docbook strings. jsf.projectType.detail.Properties=For Java properties files. @@ -52,7 +52,6 @@ jsf.projectType.detail.Xml=For XML from the Zanata REST API. jsf.projectType.detail.noSelection=A setting for older projects. jsf.projectType.detail.noSelection.message=You will not be able to upload source files from the client with this setting unless you add a project type to your config file. - #FIXME extract URL to separate property. # Note that descriptions of project types in different languages could be provided jsf.projectType.NoSelection=Unspecified @@ -106,8 +105,8 @@ jsf.IrcHelp=IRC Help ! FAQ = frequently asked questions jsf.FAQ=FAQ jsf.SiteMap=Site map - -jsf.RunningVersionInfo=#{messages['jsf.Zanata']} #{applicationConfiguration.version} (#{applicationConfiguration.scmDescribe}) +# {0} = application name (jsf.Zanata), {1} = app version, {2} = source control ID +jsf.RunningVersionInfo={0} {1} ({2}) ! © is a copyright symbol ! "Red Hat, Inc" should only be translated to an alternative legal name for the same entity. If in doubt, leave it as-is. jsf.CopyrightNotice=Copyright © 2008-14 Red Hat, Inc @@ -209,10 +208,12 @@ jsf.Translation=Translation jsf.validation.source=Source jsf.validation.target=Target jsf.validation.updated=Updated validation {0} to {1}. -jsf.CopyTrans.run=Run #{messages['jsf.CopyTrans']} -jsf.CopyTrans.cancel=Cancel #{messages['jsf.CopyTrans']} +# as a verb +jsf.CopyTrans.run=Copy Translations +jsf.CopyTrans.cancel=Cancel Translation Copy} +# as a noun (the CopyTrans feature) jsf.CopyTrans=Copy Translations -jsf.Copytrans.message=#{messages['jsf.CopyTrans']} attempts to reuse translations that have been entered in Zanata by matching them with untranslated strings in your project/version. Consequently, "Copy Translations" is best used before translation and review work is initiated on a project. +jsf.Copytrans.message="Copy Translations" attempts to reuse translations that have been entered in Zanata by matching them with untranslated strings in your project/version. Consequently, "Copy Translations" is best used before translation and review work is initiated on a project. jsf.Copytrans.message2=A translation has to pass through each of these checks before it will be copied. jsf.CopyTrans.Action.message=If all previous steps have passed, copy as translated. jsf.CopyTrans.Action.message2=Unless previously marked as fuzzy. @@ -232,8 +233,8 @@ jsf.NoProjectExists=No project exists. #------ [home] > Search Projects ------ -jsf.SearchResultsForProjectSearch=Search Results for '#{projectSearch.projectAutocomplete.query}' -jsf.projectSearch.searchQuery.title=Projects matching query '#{projectSearch.projectAutocomplete.query}' +jsf.SearchResultsForProjectSearch=Search Results for "{0}" +jsf.projectSearch.searchQuery.title=Projects matching query "{0}" #------ [home] > Projects > Create a New Project ------ @@ -282,8 +283,8 @@ jsf.ArchiveProject.Message=This will disable this project and remove it from the jsf.UnarchiveProject.Message=This will set the project's status to active and make it visible in the public projects list. jsf.project.readonly.Message=Read only prevents translations being entered. Your project will still be viewable by the public but no new translations can be added. jsf.project.writable.Message=Your project will be viewable by the public and new translations can be added. -jsf.project.LanguageRemoved=Language '{0}' has been removed from project. -jsf.project.LanguageAdded=Language '{0}' has been added to project. +jsf.project.LanguageRemoved=Language "{0}" has been removed from project. +jsf.project.LanguageAdded=Language "{0}" has been added to project. jsf.project.LanguageUpdateFromGlobal=Updated languages from global settings. @@ -314,10 +315,7 @@ jsf.project.EditHomePage.label=Edit Page Code jsf.project.EditHomePage.tooltip=Edit the Project's home page code as persisted. Useful when the home page cannot be edited via the project edit page. jsf.CreateVersion=Create Version jsf.ManageMaintainers=Manage Maintainers -! "Copy Trans" refers to a specific feature that copies previous versions of translations to the current version. -! You may choose an appropriate short name to refer to this feature, or keep this name as-is. -! This string is used in other strings wherever #{messages['jsf.CopyTrans']} is found, to ensure that the name is used consistently. -jsf.project.CopyTransOpts.tooltip=Help: Set this project's default #{messages['jsf.CopyTrans']} settings. +jsf.project.CopyTransOpts.tooltip=Help: Set this project's default settings for "Copy Translations". jsf.ProjectMaintainers=Project Maintainers jsf.NoMaintainers=No maintainers jsf.project.RoleRestrictions=Role Restrictions @@ -338,15 +336,28 @@ jsf.tooltip.ShowExample=Show example jsf.tooltip.HideExample=Hide example jsf.tooltip.TranslateOptions=Translate Options jsf.tooltip.DocumentOptions=Document Options -jsf.project.version.latest=Latest +jsf.tooltip.options=Options jsf.Permissions=Permissions -jsf.project.MaintainerRemoved=Maintainer '{0}' has been removed from project. +jsf.project.MaintainerRemoved=Maintainer "{0}" has been removed from project. jsf.project.NeedAtLeastOneMaintainer=Need at least 1 maintainer in project. -jsf.project.MaintainerAdded=Maintainer '{0}' has been added to project. -jsf.project.status.updated=Updated project status '{0}'. +jsf.project.MaintainerAdded=Maintainer "{0}" has been added to project. +jsf.project.status.updated=Updated project status "{0}". jsf.field.optional=(optional) jsf.field.repository=Repository +jsf.CopyVersion=Copy version +jsf.copyVersion.versionPage.label=Copy to new version +jsf.copyVersion.Cancelled=Cancelled copy of version {0}. +jsf.copyVersion.Completed=Finished copying version {0}. +jsf.copyVersion.cancel.message=Stop copying version +jsf.copyVersion.stop=Stop +jsf.copyVersion.started=Creating version {0} from {1} +jsf.copyVersion.label=Copy from previous version +jsf.copyVersion.processedDocuments=Processed document {0} of {1} +jsf.copyVersion.versionSettingsDisabled=Settings option is disabled temporarily due to copy version. +jsf.copyVersion.processedDocumentsAndPercent=Processed document {0} of {1} - {2}% +jsf.copyVersion.cancel.confirm=Are you sure you wish to stop this copy process? This may leave this version in read-only status (can be updated by project maintainers in settings page) + #------ [home] > Projects > [project-id] > Manage Maintainers ------ #------ [home] > Groups > [group-id] > Manage Maintainers ------ @@ -355,13 +366,19 @@ jsf.AreYouSureYouWishToRemoveThisPersonAsProjectMaintainer=Are you sure you wish jsf.AddGroupMaintainer=New Maintainer jsf.AreYouSureYouWishToRemoveThisPersonAsGroupMaintainer=Are you sure you wish to remove this person as group maintainer? jsf.YouAreNoLongerMaintainerForThisProject=You are no longer a maintainer for this project. +jsf.group.RemoveLanguage.sr.label=Remove +jsf.group.RemoveLanguage.title=Remove Language +jsf.group.RemoveVersion.sr.label=Remove +jsf.group.RemoveVersion.title=Remove Version +jsf.group.RemoveMaintainer.sr.label=Remove +jsf.group.RemoveMaintainer.title=Remove Maintainer #------ [home] > Projects > [project-id] > Copy Trans Options ------ #------ [home] > Projects > [project-id] > [version-id] > Copy Translations ------ # Some of these strings are only visible while copytrans is running -jsf.project.CopyTransOpts.title=#{messages['jsf.CopyTrans']} Options -jsf.project.CopyTransOpts.updated=#{messages['jsf.CopyTrans']} options updated. +jsf.project.CopyTransOpts.title="Copy Translations" Options +jsf.project.CopyTransOpts.updated="Copy Translations" options updated. jsf.iteration.CopyTrans.Condition=Condition jsf.iteration.CopyTrans.Condition.onContentMismatch=On content mismatch jsf.iteration.CopyTrans.Condition.onContentMismatch.details=If the translations are not identical @@ -387,12 +404,11 @@ jsf.iteration.archive.Message=This will disable this version and remove it from jsf.iteration.unarchive.Message=This will set the version's status to active and make it visible in the public projects list. jsf.iteration.readonly.Message=Read only prevents translations being entered. This version will still be viewable by the public but no new translations can be added. jsf.iteration.writable.Message=This version will be viewable by the public and new translations can be added. -jsf.iteration.status.updated=Updated version status '{0}'. -jsf.iteration.LanguageRemoved=Language '{0}' has been removed from version. -jsf.iteration.LanguageAdded=Language '{0}' has been added to version. +jsf.iteration.status.updated=Updated version status "{0}". +jsf.iteration.LanguageRemoved=Language "{0}" has been removed from version. +jsf.iteration.LanguageAdded=Language "{0}" has been added to version. jsf.iteration.requireReview.enabled=Enabled translation review jsf.iteration.requireReview.disabled=Disabled translation review -jsf.iteration.copyTrans.start.question=Do you want to run #{messages['jsf.CopyTrans']} on this version? jsf.iteration.CopyTrans.message=This is automatically run whenever a document is uploaded jsf.iteration.CopyProjectType.label=Copy project type from project jsf.iteration.CopyProjectValidation.label=Copy translation validation settings from project @@ -400,14 +416,8 @@ jsf.iteration.CopyProjectValidations.message=Copied validation settings from pro jsf.iteration.CopyProjectType.message=Copied project type from project jsf.iteration.inheriteLanguage.label=Inherit languages from project settings. -! used in coloured display tiles -#FIXME this is actually longer, may not be necessary or should be named better -jsf.iteration.CopyTrans.Action.short.downgradeToFuzzy=Copy as Fuzzy -jsf.iteration.CopyTrans.Action.ignore=Next Condition ! used in coloured display tiles #FIXME this looks like a duplicate -jsf.iteration.CopyTrans.Action.short.ignore=Next Condition -jsf.iteration.CopyTrans.Help.ignore=This condition will not be taken into account to determine whether a translation is reused or not. jsf.Translated=Translated jsf.Words=words jsf.WordsRemaining=words remaining @@ -415,12 +425,11 @@ jsf.LastUpdated=last updated jsf.LastUpdatedByYou=last updated by you jsf.iteration.CopyTrans.Help.translated=Translation will be reused and marked as Translated if it has not been skipped or marked as fuzzy already. jsf.Start=Start -jsf.CopyTrans.ClickHereToViewProgress=Please click here to view progress. jsf.iteration.CopyTrans.NoDocuments=There are no documents in this project version. -jsf.iteration.CopyTrans.Started=#{messages['jsf.CopyTrans']} started. -jsf.iteration.CopyTrans.Completed=#{messages['jsf.CopyTrans']} completed. -jsf.iteration.CopyTrans.Cancelled=#{messages['jsf.CopyTrans']} cancelled. -jsf.iteration.CopyTransOpts.tooltip=Help: Set this version's #{messages['jsf.CopyTrans']} settings. +jsf.iteration.CopyTrans.Started="Copy Translations" started. +jsf.iteration.CopyTrans.Completed="Copy Translations" completed. +jsf.iteration.CopyTrans.Cancelled="Copy Translations" cancelled. +jsf.iteration.CopyTransOpts.tooltip=Help: Set this version's "Copy Translations" settings. jsf.iteration.tooltip.readonly=This version is currently read only @@ -457,6 +466,8 @@ jsf.stats.TotalHoursRemaining=total hours remaining jsf.stats.ShortHoursSuffix=hrs ! shown in place of statistics when no statistics are available (e.g. if there are no documents) jsf.NoContent=(No Content) +jsf.document.noContent.label=No content +jsf.document.noContent.title=Document has no content ! label for time and username of most recent translation jsf.LastTranslated=Last translated @@ -465,9 +476,9 @@ jsf.GenerateProjectConfig=Generate project configuration file (zanata.xml) jsf.iteration.CopyTrans.title=Copy approved translations from other similar documents. jsf.JoinedGroups=Joined Groups -jsf.iteration.CopyTrans.inProgress=#{messages['jsf.CopyTrans']} in progress... -jsf.iteration.CopyTrans.estimatedTimeRemaining=Time Remaining: #{copyTransAction.copyTransEstimatedTimeLeft} -jsf.iteration.CopyTrans.processedItems=Processed message ##{copyTransAction.currentProgress} of #{copyTransAction.maxProgress} +jsf.iteration.CopyTrans.inProgress="Copy Translations" in progress... +jsf.iteration.CopyTrans.estimatedTimeRemaining=Time Remaining: {0} +jsf.iteration.CopyTrans.processedItems=Processed message {0} of {1} jsf.iteration.requireTranslationReview=Require translation review jsf.iteration.requireReview.message=If review is required an extra "reviewed" state will be added to translations and will not be considered finalised until a translation has reached this state. jsf.iteration.requireReview.help=Help: Turning review on or off @@ -518,7 +529,7 @@ jsf.iteration.files.DeleteDocument=Delete this document jsf.iteration.files.DownloadDocument=Download this document [{0}] jsf.iteration.files.UploadNewSourceDocument=Upload new source document jsf.iteration.files.FilenameWithSemicolonNotSupported=Zanata does not support filenames that contain a semicolon. -jsf.SupportedUploadFormats=Supported types: .pot .dtd .txt .odt .fodt .odp .fodp .ods .fods .odg .fodg .odb .odf +jsf.SupportedUploadFormats=Supported types: .pot .dtd .txt .html .htm .odt .odp .ods .odg .idml .srt .vtt .sub .sbt jsf.SourceLanguage=Source Language jsf.iteration.files.DocumentPath=Document Path jsf.iteration.files.CustomParams=Custom Parsing Parameters @@ -529,18 +540,16 @@ jsf.iteration.files.CustomParams.linkText=Wiki page for Custom Parsing Parameter jsf.iteration.files.UploadFailed=Upload Failed! Caused by: jsf.ConfigFileForOfflineTranslation=Offline Translation Config File -jsf.GenerateProjectConfigSingleLocale=Generate project configuration file (zanata.xml) for this version with locale #{projectIterationFilesAction.localeId} -jsf.GenerateProjectConfigForOfflineTranslation=Generate project configuration file (zanata.xml) for this version with locale #{projectIterationFilesAction.localeId}, using special project type 'offlinepo' for use in offline translation of po files. jsf.ConfigFileDisabledProjectNotSet=Disabled because maintainer has not set project type for this project. jsf.iteration.files.DownloadTranslated=Download translated [{0}] jsf.iteration.files.DownloadAll=Download All (zip) jsf.iteration.files.DownloadAllOfflinePo=Download All for Offline Translation -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed=The project type must be set to 'Gettext' or 'Podir'. Contact the project maintainer. +jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed=The project type must be set to "Gettext" or "Podir". Contact the project maintainer. jsf.iteration.files.DownloadAllFiles.ProjectTypeNotSet=The project type for this iteration has not been set. Contact the project maintainer. jsf.iteration.files.ConfirmDownloadAllFiles=Your download will be prepared and may take a few minutes to complete. Is this ok? -! #{...currentProgress} represents the number of documents that have been processed, #{...maxProgress} represents the total number of documents -jsf.generatezip.ProgressLabel=#{projectIterationZipFileAction.zipFilePrepHandle.currentProgress} of #{projectIterationZipFileAction.zipFilePrepHandle.maxProgress} +! {0} represents the number of documents that have been processed, {1} represents the total number of documents +jsf.generatezip.ProgressLabel={0} of {1} jsf.iteration.files.WhyCantITranslate=Why can't I translate? jsf.iteration.files.translateDenied.NotLoggedIn=You are not logged In. @@ -559,6 +568,45 @@ jsf.iteration.TranslateOnline=Translate Online jsf.iteration.ViewOnline=View Online + + +#------ [home] > Projects > [project-id] > [version-id] > Settings ------ +jsf.upload.UploadNewDocuments=Upload new documents +jsf.upload.NotSupported=This project-version is not set to a type that supports web upload +jsf.upload.ClientUploadInstructions=You can use the Zanata client to upload documents. Instructions for uploading documents with the client can be found in {0}Help - Document Upload with Client{1}. +jsf.upload.ChangeProjectTypeInstructions=A maintainer of this project can set or change the type in the project and version settings. +! {0} and {1} are placeholders for html tags. Their order should not be changed. +jsf.upload.DragDropOrBrowseFiles=Drag and drop or {0}browse files{1} +jsf.upload.MaximumFileSize=Maximum file size is {0}MB +jsf.upload.MaximumNumberOfFiles=Maximum number of files is {0} +! the variable is a comma-separated list of file extensions that can be uploaded +jsf.upload.AcceptedFileTypes=Accepted: {0} +jsf.upload.AdvancedSettings=Advanced settings +jsf.upload.FilePath=File Path +jsf.upload.FileParameters=File Parameters +jsf.upload.FileParametersHelp=Custom file parameters are not needed in most cases. Click here to open the help page. +jsf.upload.ClickToExpand=Click to expand +jsf.upload.NoDocumentsQueued=No documents queued +jsf.upload.OneDocumentQueued=1 document queued. +jsf.upload.NumberOfDocumentsQueued={documentCount} documents queued. +jsf.upload.UploadDocuments=Upload Documents +jsf.upload.RemoveDocument=Remove document +jsf.upload.SuccessfullyUploaded=Successfully uploaded +jsf.upload.UploadedOfTotal=Uploaded {uploaded} of {total} files. +jsf.upload.UploadedOfTotalWithFailures=Uploaded {uploaded} of {total} files. {failed} uploads failed. +jsf.upload.FailedToUpload=Failed to upload this file. +jsf.upload.ConfirmStopUploading=Do you really want to stop uploading files? +jsf.upload.ConfirmInterruptByLeavingPage=Do you really want to interrupt your uploading files by leaving this page? +jsf.upload.NotSupportedFileType="{filename}" is not a supported file type. +jsf.upload.FileIsTooLarge="{filename}" is too large. +jsf.upload.TooManyFiles=Too many files. You can upload more files after the current files are uploaded. +jsf.upload.SessionTimedOut=Your session has timed out. Please log in again before uploading files. +jsf.upload.ServerStoppedResponding=Some files could not be uploaded. The server stopped responding. +jsf.upload.NotLoggedIn=You are not logged in. Open a separate tab or window to log in, then try again. +jsf.upload.UploadInProgress=You already have an upload in progress. Wait for the other upload to finish, then try again. Uploads may take up to 5 minutes to finish processing. +jsf.upload.ErrorWhileChecking=Got an error while checking if it is ok to upload: {error}. If the error persists, please report it using the "Report a problem" link at the bottom of the page. +jsf.upload.UploadedBytesExceedFileSize=Uploaded bytes exceed file size + #------ [home] > Groups ------ jsf.NoGroups=No groups jsf.groups.ShowActiveGroups=Show active groups @@ -574,19 +622,19 @@ jsf.NoProjectsInGroup=No projects in group jsf.SelectALanguageFromList=Select a language from list. jsf.SelectADocumentFromList=Select a document from list. jsf.SelectAProjectFromList=Select a project from list. -jsf.LanguageRemoveFromGroup=Language '{0}' has been removed from group. -jsf.VersionRemoveFromGroup=Version '{0}' of Project '{1}' has been removed from group. -jsf.LanguageAddedToGroup=Language '{0}' has been added to group. -jsf.VersionAddedToGroup=Version '{0}' of Project '{1}' has been added to group. -jsf.LanguageAlreadyInGroup=Language '{0}' is already added to group. +jsf.LanguageRemoveFromGroup=Language "{0}" has been removed from group. +jsf.VersionRemoveFromGroup=Version "{0}" of Project "{1}" has been removed from group. +jsf.LanguageAddedToGroup=Language "{0}" has been added to group. +jsf.VersionAddedToGroup=Version "{0}" of Project "{1}" has been added to group. +jsf.LanguageAlreadyInGroup=Language "{0}" is already added to group. jsf.InvalidProjectVersion=Invalid project version -jsf.VersionAlreadyInGroup=Version '{0}' is already added to group. +jsf.VersionAlreadyInGroup=Version "{0}" is already added to group. jsf.ArchiveThisGroup=Archive this Group jsf.UnArchiveThisGroup=Unarchive this Group -jsf.MaintainerRemoveFromGroup=Maintainer '{0}' has been removed from group. -jsf.MaintainerAddedToGroup=Maintainer '{0}' has been added to group. +jsf.MaintainerRemoveFromGroup=Maintainer "{0}" has been removed from group. +jsf.MaintainerAddedToGroup=Maintainer "{0}" has been added to group. jsf.InvalidUsername=Invalid username. -jsf.UserIsAMaintainer=User '{0}' is already a maintainer of group. +jsf.UserIsAMaintainer=User "{0}" is already a maintainer of group. jsf.ProjectMissingLanguage={0} project missing for this language jsf.ProjectsMissingLanguage={0} projects missing for this language jsf.LanguageMissingProject={0} language missing for this project @@ -634,9 +682,10 @@ jsf.Members=Members #------ [home] > Languages > [locale-id] ------ -jsf.LanguageTeamTitle=#{languageTeamAction.locale.retrieveDisplayName()} Team -! number of translators who are members of this language team -jsf.SizeMembers=#{languageTeamAction.locale.members.size} members +# {0} = locale display name +jsf.LanguageTeamTitle={0} Team +! {0} = number of translators who are members of this language team +jsf.SizeMembers={0} members jsf.Coordinator=Coordinator jsf.JoinLanguageTeam=Join Language Team jsf.LeaveLanguageTeam=Leave Language Team @@ -649,7 +698,7 @@ jsf.Loading=Loading... jsf.AlreadyInTeam=Already in Team jsf.Reviewer=Reviewer jsf.Translator=Translator -jsf.RequestRoleAs=Request the following roles in the '#{sendEmail.locale.localeId.id}' language team: +jsf.RequestRoleAs=Request the following roles in the "{0}" language team: #------ [home] > Help ------ @@ -670,8 +719,13 @@ jsf.Glossary.TreatSourceCommentsAsTarget=Treat source comments and ref as target jsf.Glossary.TreatSourceCommentsAsTarget.Title=When checked, source comments and references will be used as target comments jsf.Glossary.CommentColumnNames=Comment column names jsf.Glossary.CommentColumnNames.Title=Customized comment column headers for csv file format. Format of CSV: {source locale},{locale1},{locale2},...,{pos},{description} OR {source locale},{locale},{locale},...,{description1},{description2},... (only applies for CSV file format) -jsf.ThisActionCannotBeUndone=This action cannot be undone -jsf.SelectLocaleToDelete=Select locale to delete +jsf.Glossary.empty=No glossary +jsf.Glossary.upload=Upload glossary +jsf.Glossary.delete=Delete glossary +jsf.Glossary.options=Glossary options +jsf.Glossary.entries.label=Glossary entries +jsf.Glossary.delete.confirm=Are you sure you want to delete glossary in "{0}"? +jsf.Glossary.deleted=Glossary deleted: {0} entries in {1} @@ -690,10 +744,10 @@ jsf.TermsOfUse=Terms of Use jsf.register.LoginUsingOpenId=You can also login using Open Id Here. jsf.PleaseContactAdministrationToGetRegistrationLink=Please contact administration to get registration link. -jsf.register.WithZanata=Sign up with your username +jsf.register.WithZanata=Sign up with Zanata jsf.register.FullName.label=Full Name jsf.register.WithOther.label=or sign up using an existing account -jsf.register.agreeToTOS=By signing up for Zanata, you agree to our #{messages['jsf.TermsOfUse']}. +jsf.register.agreeToTOS=By signing up for Zanata, you agree to our Terms of Use. jsf.register.AlreadyHaveAccount.label=Already have an account? jsf.register.LogIn.label=Log In @@ -708,20 +762,13 @@ jsf.ResetYourPassword=Reset Your Password jsf.NewPassword=New Password jsf.OldPassword=Old Password jsf.ChangePassword=Change Password -jsf.RememberMe=Remember me -jsf.login.openid.SelectProvider=How are you logging in? -jsf.login.openid.fedora=Fedora Username -jsf.login.openid.myopenid=MyOpenID User -jsf.login.openid.yahoo=Yahoo Username jsf.login.openid=Open ID -jsf.login.internal=Username jsf.login.WithZanata.label=Log in with your username jsf.login.DontHaveAnAccount.label=Don't have an account? -jsf.login.OrLoginUsing.label=or log in using an existing account +jsf.login.OrLoginUsing.label=or log in with -jsf.UsernameNotAvailable=Username "#{userAction.username}" is not available -jsf.FedoraUsername=Fedora Username +jsf.UsernameNotAvailable=Username "{0}" is not available jsf.ActivateAccount=Activate Account jsf.ValidateEmail=Validate Email @@ -733,7 +780,7 @@ jsf.or=OR jsf.inactiveaccount.UpdateAndResend=Update email address and re-send activation email: jsf.UpdateEmail=Update email address jsf.InvalidActivationKey=Invalid activation key -jsf.ActivationLinkExpired=Activation link expired. Please sign in and click "#{messages['jsf.ResendActivationEmail']}". +jsf.ActivationLinkExpired=Activation link expired. Please sign in and click "Re-send activation email". @@ -784,9 +831,9 @@ jsf.identities.Verify=Verify Identity #------ [home] > My Profile > Merge Accounts ------ jsf.profile.MergeAccount=Merge Accounts -jsf.profile.MergeAccount.info=Log in to the account you want to merge. You will need to use one of the authentication methods offered below. You will be asked for further confirmation after this. -jsf.profile.MergeAccount.confirm=Do It -jsf.profile.MergeAccount.confirmationMessage=You are about to merge in the following account:

Username: #{accountMergeAction.obsoleteAccount.username}
Name: #{accountMergeAction.obsoleteAccount.person.name}
Email: #{accountMergeAction.obsoleteAccount.person.email}

This change is permanent and cannot be taken back.

The account mentioned above will be inactivated and all of its permissions revoked. Your current account will inherit all these permissions.

Are you sure you want to do this? +jsf.profile.MergeAccount.info=Log in with another existing account to merge it into your current account +jsf.profile.MergeAccount.confirm=Merge +jsf.profile.MergeAccount.confirmationMessage=You are about to merge in the following account:

Username: {0}
Name: {1}
Email: {2}

This change is permanent and cannot be undone.

The account mentioned above will be deactivated and all of its permissions revoked. Your current account will inherit all these permissions.

Are you sure you want to do this? @@ -818,11 +865,11 @@ jsf.EmailDomainName=Email Domain Name jsf.EmailDomainNameToolTip=Email Domain Name should be in example.com format. jsf.EmailDomainNameExample=e.g. redhat.com jsf.config.AdminEmail=Contact Admin Address -jsf.config.AdminEmail.tooltip=Email will be sent to these addresses when the 'Contact Admin' form is used. +jsf.config.AdminEmail.tooltip=Email will be sent to these addresses when the "Contact Admin" form is used. jsf.config.AdminEmail.DoesNotChangeUserEmail=This field does not change the individual email address for any admin users. jsf.email.EmailListToolTip=Email addresses should be separated by a single comma (,) jsf.config.FromEmailAddr=From Email Address -jsf.config.FromEmailAddr.tooltip=This will be used in the 'from' field of any emails sent by this zanata server +jsf.config.FromEmailAddr.tooltip=This will be used in the "from" field of any emails sent by this zanata server jsf.config.EnableLogEmails=Enable Log emails jsf.config.EnableLogEmails.tooltip=Enables or disables the sending of Zanata diagnostics log information via email. jsf.config.LogDestEmail=Log Destination email addresses @@ -841,7 +888,9 @@ jsf.config.MaxConcurrentRequestsPerApiKey=Max concurrent requests per API key jsf.config.MaxConcurrentRequestsPerApiKeytooltip=Max concurrent requests per API key. Once over the limit server will return status code 403. 0 means no limit. Default(blank) is 6. jsf.config.MaxActiveRequestsPerApiKey=Max active requests per API key jsf.config.MaxActiveRequestsPerApiKeytooltip=Max active requests per API key. Request may block. 0 means no limit. Default(blank) is 2. If this is greater than max concurrent request limit, it will have no effect. - +jsf.config.MaxFilesPerUpload=Max files per upload +jsf.config.MaxFilesPerUploadTooltip=Maximum number of files a user can queue for upload in the web upload dialog. +jsf.config.MaxFilesPerUploadDefault=default is 100 #------ [home] > Administration > Manage Users ------ @@ -913,14 +962,18 @@ jsf.ManageSearch.SelectNone=Clear Selection jsf.ManageSearch.PerformSelectedActions=Perform Selected Actions jsf.ManageSearch.CurrentProgress=Current Progress jsf.ManageSearch.NoOperationsRunning=No operations are running -jsf.ManageSearch.Completed=Completed successfully (ran for #{reindexAction.elapsedTime}) -jsf.ManageSearch.Aborted=Aborted by user (ran for #{reindexAction.elapsedTime}) +# {0} = elapsed time +jsf.ManageSearch.Completed=Completed successfully (ran for {0}) +# {0} = elapsed time +jsf.ManageSearch.Aborted=Aborted by user (ran for {0}) jsf.manageSearch.ErrorMessage=Due to an error, some objects could not be reindexed. See server log for details. jsf.manageSearch.PleaseReindex=Please reindex again to ensure the search index is up-to-date. -jsf.manageSearch.ProgressMessage=#{reindexAction.reindexProgress} of #{reindexAction.reindexCount} operations complete -jsf.manageSearch.CurrentTable=Processing table: #{reindexAction.currentClass} -jsf.ManageSearch.ElapsedTime=Running for: #{reindexAction.elapsedTime} -jsf.ManageSearch.RemainingTime=Remaining (approx): #{reindexAction.estimatedTimeRemaining} +jsf.manageSearch.ProgressMessage={0} of {1} operations complete +jsf.manageSearch.CurrentTable=Processing table: {0} +# {0} = elapsed time +jsf.ManageSearch.ElapsedTime=Running for: {0} +# {0} = estimated time remaining +jsf.ManageSearch.RemainingTime=Remaining (approx): {0} jsf.ManageSearch.Abort=Abort @@ -1007,21 +1060,23 @@ jsf.email.Send=Send Message jsf.NoProjects=No projects to display. jsf.RequestToAddProjectVersionToGroup=Request to add project version(s) to group \"{0}\" jsf.NoProjectVersionSelected=No project version selected. -jsf.ClickSendMessageToProceedRequest=Enter additional information and click 'Send Message' to proceed +jsf.ClickSendMessageToProceedRequest=Enter additional information and click "Send Message" to proceed jsf.RequestAddProjectToGroup=Request to add a project version to \"{0}\" jsf.RequestJoinGroup=Request to add project version to group jsf.AlreadyInGroup=Already in Group jsf.email.joingrouprequest.AdditionalInfoMessage=To ensure your request is processed without delay, please provide any additional information that will help the group maintainers to process your request. !FIXME make key similar to related keys -jsf.RequestToJoinLanguageTeamTitle=Request To Join '#{sendEmail.locale.localeId.id}' Language Team -jsf.RequestRoleLanguageTeamTitle=Request Role in '#{sendEmail.locale.localeId.id}' Language Team +jsf.RequestToJoinLanguageTeamTitle=Request To Join "{0}" Language Team +jsf.RequestRoleLanguageTeamTitle=Request Role in "{0}" Language Team -jsf.email.JoinGroupRequest.Subject=Request to join group '#{versionGroupJoinAction.groupName}' -jsf.email.joinrequest.Subject=User '#{sendEmail.fromLoginName}' wants to join the '#{sendEmail.locale.localeId.id}' language team -jsf.email.rolerequest.Subject=User '#{sendEmail.fromLoginName}' request for additional role in '#{sendEmail.locale.localeId.id}' language team +jsf.email.JoinGroupRequest.Subject=Request to join group "{0}" +jsf.email.joinrequest.Subject=User "{0}" wants to join the "{1}" language team +jsf.email.rolerequest.Subject=User "{0}" request for additional role in "{1}" language team jsf.email.AdditionalInfoMessage=To ensure your request is processed without delay, please provide any additional information that will help the team coordinators identify you and process your request. -jsf.email.ContactCoordinatorTitle=Contact '#{sendEmail.locale.retrieveDisplayName()}' Coordinator -jsf.contactLanguageTeamCoordinatorForLocale=Contact '#{sendEmail.locale.localeId.id} (#{sendEmail.locale.retrieveNativeName()})' Language Team Coordinators +# {0} = locale display name +jsf.email.ContactCoordinatorTitle=Contact "{0}" Coordinator +# {0} = locale ID, {1} = locale native name +jsf.contactLanguageTeamCoordinatorForLocale=Contact "{0} ({1})" Language Team Coordinators @@ -1034,8 +1089,8 @@ jsf.email.GeneratedFromZanataServerAt=This message generated by Zanata running a #------ activation email ------ jsf.Account.ActivationMessage=You will soon receive an email with a link to activate your account. jsf.email.activation.Subject=Zanata Account Activation -jsf.email.activation.register.DearName=Dear #{emailServiceImpl.toName}, -jsf.email.activation.profile.DearName=Dear #{newProfileAction.name}, +jsf.email.activation.register.DearName=Dear {0}, +jsf.email.activation.profile.DearName=Dear {0}, jsf.email.activation.ClickLinkToActivateAccount=Please click on the following link to activate your account: jsf.email.activation.Link=Account activation link jsf.email.alternate.copyPasteMessage=Alternatively, you can copy and paste the following URL into your browser: @@ -1044,66 +1099,73 @@ jsf.UrlExpireMessage=URL will expire after 24 hours. #------ account-validation email ------ jsf.email.accountchange.Subject=Zanata Email Change Confirmation -jsf.email.accountchange.DearName=Dear #{profileAction.name}, -jsf.email.accountchange.Message=Zanata has received a request to update your email to #{profileAction.email} +jsf.email.accountchange.DearName=Dear {0}, +jsf.email.accountchange.Message=Zanata has received a request to update your email to {0} jsf.email.accountchange.Message2=If you did not request this action or are unsure about why it was done, please contact the Zanata System administrators as soon as possible. jsf.email.accountchange.ConfirmationLink=Click here to confirm email change +jsf.email.accountchange.SentNotification=You will soon receive an email with a link to activate your email account change. #------ username-change email ------ jsf.email.usernamechange.Subject=Your Zanata username has been changed. -jsf.email.usernamechange.DearName=Dear #{userAction.getName(userAction.username)}, +jsf.email.usernamechange.DearName=Dear {0}, jsf.email.usernamechange.Content=Your Zanata username has been recently changed by one of the System Administrators. If you did not request this action or are unsure about why it was done, please contact the Zanata System administrators as soon as possible. -jsf.email.usernamechange.YourNewUsername=Your new username is '#{userAction.username}' +jsf.email.usernamechange.YourNewUsername=Your new username is "{0}" jsf.email.usernamechange.ResetPassword=You now need to reset your password. To do this, please click on the link below: jsf.email.usernamechange.ClickLinkForPasswordReset=Click Here to Reset Your Password +jsf.email.usernamechange.SentNotification=An email about the change of username has been sent to the user. #------ password-reset email ------ jsf.email.passwordreset.Subject=Zanata Reset Password Request -jsf.email.passwordreset.DearName=Dear #{passwordResetRequest.account.person.name}, +jsf.email.passwordreset.DearName=Dear {0}, jsf.email.passwordreset.FollowLinkToResetPassword=Please follow the link below to reset the password for your account. jsf.email.passwordreset.IgnoreIfNotRequested=If you haven't explicitly requested a password reset, you can ignore this request. +jsf.email.passwordreset.SentNotification=You will soon receive an email with a link to reset your password. #------ contact-admin email ------ jsf.email.admin.SentNotification=Your message has been sent to the administrator ! this string is the start of the subject. The subject entered by the user is appended to this. -jsf.email.admin.SubjectPrefix=Zanata user email from '#{sendEmail.fromLoginName}': +jsf.email.admin.SubjectPrefix=Zanata user email from "{0}": jsf.ZanataAdministrator=Zanata Administrator jsf.email.admin.DearAdmin=Dear Administrator, -jsf.email.admin.UserMessageIntro=Zanata user '#{sendEmail.fromName}' with id '#{sendEmail.fromLoginName}' has sent the following message: -jsf.email.ReplyInstructions=You can reply to #{sendEmail.fromName} at #{sendEmail.replyEmail} +jsf.email.admin.UserMessageIntro=Zanata user "{0}" with id "{1}" has sent the following message: +jsf.email.ReplyInstructions=You can reply to {0} at {1} jsf.email.admin.ReceivedReason=You are an administrator in the system configuration jsf.email.admin.user.ReceivedReason=You are an administrator #------ contact-language-team-coordinator email ------ -jsf.email.coordinator.SentNotification=Your message has been sent to the #{sendEmail.locale.retrieveNativeName()} language team +jsf.email.coordinator.SentNotification=Your message has been sent to the {0} language team ! this string is the start of the subject. The subject entered by the user is appended to this. -jsf.email.coordinator.SubjectPrefix=Zanata: #{sendEmail.locale.localeId.id} Language Team: message from '#{sendEmail.fromLoginName}': +jsf.email.coordinator.SubjectPrefix=Zanata: {0} Language Team: message from "{1}": jsf.email.coordinator.DearCoordinator=Dear Language Team Coordinator, -jsf.email.coordinator.UserMessageIntro=Zanata user '#{sendEmail.fromName}' with id '#{sendEmail.fromLoginName}' has sent the following message to the #{sendEmail.locale.localeId.id} (#{sendEmail.locale.retrieveNativeName()}) Language Team: -jsf.email.coordinator.ResponseInstructions=You can click the link below to go directly to the #{sendEmail.locale.localeId.id} Language Team Page. Please reply to #{sendEmail.fromName} at #{sendEmail.replyEmail} when you have finished processing their request. -jsf.email.coordinator.ReceivedReason=You are coordinator in '#{sendEmail.locale.retrieveNativeName()}' language team +# name, loginName, localeId, nativeName +jsf.email.coordinator.UserMessageIntro=Zanata user "{0}" with id "{1}" has sent the following message to the {2} ({3}) Language Team: +jsf.email.coordinator.ResponseInstructions=You can click the link below to go directly to the {0} Language Team Page. Please reply to {1} at {2} when you have finished processing this request. +jsf.email.coordinator.ReceivedReason=You are a coordinator in the "{0}" language team #------ request-to-join-language email ------ -jsf.email.joinrequest.UserRequestingToJoin=Zanata user '#{sendEmail.fromName}' with id '#{sendEmail.fromLoginName}' is requesting to join the #{sendEmail.locale.localeId.id} (#{sendEmail.locale.retrieveNativeName()}) Language Team -jsf.email.joinrequest.AddUserInstructions=You can add #{sendEmail.fromName} to the #{sendEmail.locale.localeId.id} team as translator using the "#{messages['jsf.AddTeamMember']}" action on the language team page and searching for '#{sendEmail.fromLoginName}'. +# name, loginName, localeId, nativeName +jsf.email.joinrequest.UserRequestingToJoin=Zanata user "{0}" with id "{1}" is requesting to join the {2} ({3}) Language Team +jsf.email.joinrequest.AddUserInstructions=You can add {0} to the {1} team as translator using the "Add Team Member" action on the language team page and searching for "{2}". jsf.email.joinrequest.RoleRequested=Roles requested: #------ request-role-language email ------ -jsf.email.rolerequest.UserRequestingRole=Zanata user '#{sendEmail.fromName}' with id '#{sendEmail.fromLoginName}' is requesting the following role in #{sendEmail.locale.localeId.id} (#{sendEmail.locale.retrieveNativeName()}) Language Team: -jsf.email.rolerequest.AddUserInstructions=You can assign #{sendEmail.fromName} to requested role in #{sendEmail.locale.localeId.id} team on the language team page. +# name, loginName, localeId, nativeName +jsf.email.rolerequest.UserRequestingRole=Zanata user "{0}" with id "{1}" is requesting the following role in {2} ({3}) Language Team: +jsf.email.rolerequest.AddUserInstructions=You can assign {0} to requested role in {1} team on the language team page. #------ request-to-join-group email ------ -jsf.email.group.maintainer.SentNotification=Your message has been sent to the \'#{versionGroupJoinAction.groupName}\' group maintainer +jsf.email.group.maintainer.SentNotification=Your message has been sent to the "{0}" group maintainer jsf.email.maintainer.DearMaintainer=Dear Group Maintainer, -jsf.email.joingrouprequest.RequestingToJoinGroup=Zanata user '#{sendEmail.fromName}' with id '#{sendEmail.fromLoginName}' is requesting project version to be added to group '#{versionGroupJoinAction.groupName}'. -jsf.email.UserMessageIntro=#{sendEmail.fromName} has included the following message with their request: -jsf.email.JoinGroupRequest.ResponseInstructions=Click the link below to go act on the request. Please reply to #{sendEmail.fromName} at #{sendEmail.replyEmail} when you have finished processing their request. -jsf.email.group.maintainer.ReceivedReason=You are maintainer in group '#{versionGroupJoinAction.groupName}' +# name, loginName, groupName +jsf.email.joingrouprequest.RequestingToJoinGroup=Zanata user "{0}" with id "{1}" is requesting project version to be added to group "{2}". +jsf.email.UserMessageIntro={0} has included the following message with this request: +jsf.email.JoinGroupRequest.ResponseInstructions=Click the link below to go act on the request. Please reply to {0} at {1} when you have finished processing this request. +jsf.email.group.maintainer.ReceivedReason=You are maintainer in group "{0}" diff --git a/zanata-war/src/main/resources/messages_bg.properties b/zanata-war/src/main/resources/messages_bg.properties deleted file mode 100644 index b02777e27b..0000000000 --- a/zanata-war/src/main/resources/messages_bg.properties +++ /dev/null @@ -1,140 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -up=\u2191 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -down=\u2193 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -left=\u2039 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -right=\u203A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginFailed=\u041D\u0435\u0443\u0441\u043F\u0435\u0448\u0435\u043D \u0432\u0445\u043E\u0434 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginSuccessful=\u0417\u0434\u0440\u0430\u0432\u0435\u0439, \#0 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NotLoggedIn=\u041C\u043E\u043B\u044F \u043F\u044A\u0440\u0432\u043E \u0441\u0435 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0430\u0439\u0442\u0435 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TransactionFailed=\u0422\u0440\u0430\u043D\u0437\u0430\u043A\u0446\u0438\u044F \u043D\u0435 \u0435 \u0443\u0441\u043F\u044F\u043B\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NoConversation=\u0420\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u044A\u0442 \u0435 \u043F\u0440\u0438\u043A\u043B\u044E\u0447\u0438\u043B, \u0438\u0437\u0442\u0435\u043A\u043B\u043E \u043C\u0443 \u0435 \u0432\u0440\u0435\u043C\u0435\u0442\u043E \u0438\u043B\u0438 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0432\u0430 \u0434\u0440\u0443\u0433\u0430 \u0437\u0430\u044F\u0432\u043A\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.IllegalNavigation=\u041D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0430 \u043D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessEnded=\u041F\u0440\u043E\u0446\u0435\u0441 \#0 \u0435 \u043F\u0440\u0438\u043A\u043B\u044E\u0447\u0438\u043B -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessNotFound=\u041F\u0440\u043E\u0446\u0435\u0441 \#0 \u043D\u0435 \u0435 \u043D\u0430\u043C\u0435\u0440\u0435\u043D -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskEnded=\u0417\u0430\u0434\u0430\u0447\u0430 \#0 \u0435 \u043F\u0440\u0438\u043A\u043B\u044E\u0447\u0438\u043B\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskNotFound=\u0417\u0430\u0434\u0430\u0447\u0430 \#0 \u043D\u0435 \u0435 \u043D\u0430\u043C\u0435\u0440\u0435\u043D\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.CONVERSION=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430\u043D\u0430 \u043A\u044A\u043C \u043E\u0447\u0430\u043A\u0432\u0430\u043D\u0438\u044F \u0442\u0438\u043F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.REQUIRED=\u043F\u043E\u043B\u0435\u0442\u043E \u0435 \u0437\u0430\u0434\u044A\u043B\u0436\u0438\u0442\u0435\u043B\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.UPDATE=\u0432\u044A\u0437\u043D\u0438\u043A\u043D\u0430\u043B\u0430 \u0435 \u0433\u0440\u0435\u0448\u043A\u0430 \u043F\u0440\u0438 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0430 \u043D\u0430 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u0430\u0442\u0430 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectOne.INVALID=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0435 \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectMany.INVALID=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0435 \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E \u0441\u044A\u0441 \u0437\u043D\u0430\u043A, \u0441\u044A\u0441\u0442\u043E\u044F\u0449\u043E \u0441\u0435 \u043E\u0442 \u043D\u0443\u043B\u0430 \u0438\u043B\u0438 \u043F\u043E\u0432\u0435\u0447\u0435 \u0446\u0438\u0444\u0440\u0438, \u0441\u043B\u0435\u0434\u0432\u0430\u043D\u043E \u043F\u043E \u0438\u0437\u0431\u043E\u0440 \u043E\u0442 \u0434\u0435\u0441\u0435\u0442\u0438\u0447\u043D\u0430 \u0437\u0430\u043F\u0435\u0442\u0430\u044F \u0438 \u0434\u0440\u043E\u0431\u043D\u0430 \u0447\u0430\u0441\u0442, \u043D\u0430\u043F\u0440. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E \u0441\u044A\u0441 \u0437\u043D\u0430\u043A, \u0441\u044A\u0441\u0442\u043E\u044F\u0449\u043E \u0441\u0435 \u043E\u0442 \u043D\u0443\u043B\u0430 \u0438\u043B\u0438 \u043F\u043E\u0432\u0435\u0447\u0435 \u0446\u0438\u0444\u0440\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 'true' \u0438\u043B\u0438 'false' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 'true' \u0438\u043B\u0438 'false' (\u0432\u0441\u044F\u043A\u0430 \u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442 \u0440\u0430\u0437\u043B\u0438\u0447\u043D\u0430 \u043E\u0442 'true' \u0449\u0435 \u0441\u0435 \u0441\u043C\u044F\u0442\u0430 \u0437\u0430 'false') -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E \u043C\u0435\u0434\u0436\u0443 0 \u0438 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E \u043C\u0435\u0434\u0436\u0443 0 \u0438 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0437\u043D\u0430\u043A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0432\u0430\u043B\u0438\u0434\u0435\u043D ASCII \u0437\u043D\u0430\u043A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0434\u0430\u0442\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0434\u0430\u0442\u0430, \u043D\u0430\u043F\u0440. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043E\u0442 \u0442\u0438\u043F \u0447\u0430\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043E\u0442 \u0442\u0438\u043F \u0447\u0430\u0441, \u043D\u0430\u043F\u0440. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0434\u0430\u0442\u0430 \u0438 \u0447\u0430\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0434\u0430\u0442\u0430 \u0438 \u0447\u0430\u0441, \u043D\u0430\u043F\u0440. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=\u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0437\u0430\u0434\u0430\u0434\u0435\u043D \u043E\u0431\u0440\u0430\u0437\u0435\u0446 \u0438\u043B\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 type, \u0437\u0430 \u0434\u0430 \u0441\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430 \u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E \u043C\u0435\u0436\u0434\u0443 4.9E-324 \u0438 1.7976931348623157E308 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430 \u0434\u043E \u0438\u0437\u0431\u0440\u043E\u0435\u043D \u0442\u0438\u043F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430 \u043E\u0442 \u0438\u043B\u0438 \u0434\u043E \u0438\u0437\u0431\u0440\u043E\u0435\u043D \u0442\u0438\u043F, \u043A\u043E\u0439\u0442\u043E \u0441\u044A\u0434\u044A\u0440\u0436\u0430 \u043A\u043E\u043D\u0441\u0442\u0430\u043D\u0442\u0430\u0442\u0430 {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430 \u043E\u0442 \u0438\u043B\u0438 \u0434\u043E \u0438\u0437\u0431\u0440\u043E\u0435\u043D \u0442\u0438\u043F, \u043D\u043E \u043D\u0435 \u0435 \u043F\u043E\u0434\u0430\u0434\u0435\u043D \u043A\u043B\u0430\u0441 \u043E\u0442 \u0442\u0430\u043A\u044A\u0432 \u0442\u0438\u043F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430 \u043E\u0442 \u0438\u043B\u0438 \u0434\u043E \u0438\u0437\u0431\u0440\u043E\u0435\u043D \u0442\u0438\u043F, \u043D\u043E \u043D\u0435 \u0435 \u043F\u043E\u0434\u0430\u0434\u0435\u043D \u043A\u043B\u0430\u0441 \u043E\u0442 \u0442\u0430\u043A\u044A\u0432 \u0442\u0438\u043F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E \u043C\u0435\u0436\u0434\u0443 1.4E-45 \u0438 3.4028235E38 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E \u043C\u0435\u0436\u0434\u0443 -2147483648 \u0438 2147483647 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E \u043C\u0435\u0436\u0434\u0443 -9223372036854775808 \u0438 9223372036854775807 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0441\u0443\u043C\u0430 \u0432\u044A\u0432 \u0432\u0430\u043B\u0443\u0442\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0441\u0443\u043C\u0430 \u0432\u044A\u0432 \u0432\u0430\u043B\u0443\u0442\u0430, \u043D\u0430\u043F\u0440. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u0440\u043E\u0446\u0435\u043D\u0442 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u0440\u043E\u0446\u0435\u043D\u0442, \u043D\u0430\u043F\u0440. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT_detail=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u0446\u044F\u043B\u043E \u0447\u0438\u0441\u043B\u043E \u043C\u0435\u0436\u0434\u0443 -32768 \u0438 32767 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MAXIMUM=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u043E-\u043C\u0430\u043B\u043A\u0430 \u0438\u043B\u0438 \u0440\u0430\u0432\u043D\u0430 \u043D\u0430 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MINIMUM=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u043E-\u0433\u043E\u043B\u044F\u043C\u0430 \u0438\u043B\u0438 \u0440\u0430\u0432\u043D\u0430 \u043D\u0430 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043C\u0435\u0436\u0434\u0443 {0} \u0438 {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.TYPE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u043D\u0435 \u0435 \u043E\u0442 \u043F\u0440\u0430\u0432\u0438\u043B\u043D\u0438\u044F \u0432\u0438\u0434 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MAXIMUM=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043D\u0435 \u043F\u043E-\u0434\u044A\u043B\u0433\u0430 \u043E\u0442 {0} \u0437\u043D\u0430\u043A\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MINIMUM=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u043E-\u0434\u044A\u043B\u0433\u0430 \u043E\u0442 {0} \u0437\u043D\u0430\u043A\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MAXIMUM=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u043E-\u043C\u0430\u043B\u043A\u0430 \u0438\u043B\u0438 \u0440\u0430\u0432\u043D\u0430 \u043D\u0430 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MINIMUM=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u043E-\u0433\u043E\u043B\u044F\u043C\u0430 \u0438\u043B\u0438 \u0440\u0430\u0432\u043D\u0430 \u043D\u0430 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043C\u0435\u0436\u0434\u0443 {0} \u0438 {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.TYPE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u043D\u0435 \u0435 \u043E\u0442 \u043F\u0440\u0430\u0432\u0438\u043B\u043D\u0438\u044F \u0432\u0438\u0434 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.NOT_IN_RANGE=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043C\u0435\u0436\u0434\u0443 {0} \u0438 {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.STRING=\u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0431\u044A\u0434\u0435 \u043F\u0440\u0435\u0432\u044A\u0440\u043D\u0430\u0442\u0430 \u0432 \u043D\u0438\u0437 \u043E\u0442 \u0441\u0438\u043C\u0432\u043E\u043B\u0438 diff --git a/zanata-war/src/main/resources/messages_de.properties b/zanata-war/src/main/resources/messages_de.properties deleted file mode 100644 index 444ab2cd1a..0000000000 --- a/zanata-war/src/main/resources/messages_de.properties +++ /dev/null @@ -1,140 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -up=\u2191 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -down=\u2193 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -left=\u2039 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -right=\u203A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginFailed=Anmeldung fehlgeschlagen -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginSuccessful=Willkommen, \#0\! -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NotLoggedIn=Bitte melden Sie sich zun\u00E4chst an -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TransactionFailed=Transaktion fehlgeschlagen -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NoConversation=Der Vorgang wurde bereits beendet, verarbeitet eine andere Abfrage oder ergab eine Zeit\u00FCberschreitung -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.IllegalNavigation=Unzul\u00E4ssige Navigation -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessEnded=Prozess \#0 wurde bereits beendet -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessNotFound=Prozess \#0 nicht gefunden -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskEnded=Funktion \#0 wurde bereits beendet -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskNotFound=Funktion \#0 nicht gefunden -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.CONVERSION=Wert konnte nicht in den erwarteten Typ umgewandelt werden -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.REQUIRED=Wert erforderlich -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.UPDATE=ein Fehler ist bei der Verarbeitung der von Ihnen gesendeten Daten aufgetreten -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectOne.INVALID=Wert ung\u00FCltig -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectMany.INVALID=Wert ung\u00FCltig -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL=''{0}'' muss eine Dezimalzahl sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=''{0}'' muss eine Dezimalzahl aus keinem oder mehr Zeichen gefolgt von einem optionalen Punkt und den Nachkommastellen sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER=''{0}'' muss eine Zahl aus ein oder mehr Ziffern sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=''{0}'' muss eine Zahl aus ein oder mehr Ziffern sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN=''{0}'' muss 'true' oder 'false' sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN_detail=''{0}'' muss 'true' oder 'false' sein. Jeder Wert au\u00DFer 'true' wird als 'false' interpretiert. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE=''{0}'' muss eine Zahl zwischen 0 und 255 sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE_detail=''{0}'' muss eine Zahl zwischen 0 und 255 sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER=''{0}'' muss ein g\u00FCltiges Zeichen sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER_detail=''{0}'' muss ein g\u00FCltiges ASCII Zeichen sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE=''{0}'' konnte nicht als Datum erkannt werden. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE_detail=''{0}'' konnte nicht als Datum erkannt werden. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME=''{0}'' konnte nicht als Zeit erkannt werden. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME_detail=''{0}'' konnte nicht als Zeit erkannt werden. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME=''{0}'' konnte nicht als Datum und Zeit erkannt werden. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME_detail=''{0}'' konnte nicht als Datum und Zeit erkannt werden. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=Ein 'pattern' oder 'type' Attribut muss angegeben werden um den Wert ''{0}'' zu konvertieren. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE=''{0}'' muss eine Zahl aus ein oder mehr Ziffern sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE_detail=''{0}'' muss eine Zahl zwischen 4.9E-324 und 1.7976931348623157E308 sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM=''{0}'' muss in eine Enumeration konvertierbar sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_detail=''{0}'' muss in eine Enumeration konvertierbar sein, welche die Konstante ''{1}'' enth\u00E4lt. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=''{0}'' muss in eine Enumeration konvertierbar sein, aber es wurde keine Klasse des Typs Enum bereitgestellt. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=''{0}'' muss in eine Enumeration konvertierbar sein, aber es wurde keine Klasse des Typs Enum bereitgestellt. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT=''{0}'' muss eine Zahl aus ein oder mehr Ziffern sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT_detail=''{0}'' muss eine Zahl zwischen 1.4E-45 und 3.4028235E38 sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER=''{0}'' muss eine Zahl aus ein oder mehr Ziffern sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER_detail=''{0}'' muss eine Zahl zwischen -2147483648 und 2147483647 sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG=''{0}'' muss eine Zahl aus ein oder mehr Ziffern sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG_detail=''{0}'' muss eine Zahl zwischen -9223372036854775808 und 9223372036854775807 sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY=''{0}'' konnte nicht als ein Geldbetrag erkannt werden. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY_detail=''{0}'' konnte nicht als ein Geldbetrag erkannt werden. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT=''{0}'' konnte nicht als ein Prozentanteil erkannt werden. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT_detail=''{0}'' konnte nicht als ein Prozentanteil erkannt werden. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER=''{0}'' ist keine Zahl. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER_detail=''{0}'' ist keine Zahl. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN=''{0}'' ist kein Zahlmuster. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN_detail=''{0}'' ist kein Zahlmuster. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT=''{0}'' muss eine Zahl aus ein oder mehr Ziffern sein. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT_detail=''{0}'' muss eine Zahl zwischen -32768 und 32767 sein. Beispiel\: {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MAXIMUM=Validierungsfehler\: Der Wert ist gr\u00F6\u00DFer als das erlaubte Maximum von ''{0}'' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MINIMUM=Validierungsfehler\: Der Wert ist kleiner als das erlaubte Minimum von ''{0}'' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=Validierungsfehler\: Der Wert ist nicht zwischen den erwarteten Werten von {0} und {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.TYPE=Validierungsfehler\: Der Wert ist nicht vom korrekten Typ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MAXIMUM=Validierungsfehler\: Der Wert ist gr\u00F6\u00DFer als das erlaubte Maximum von ''{0}'' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MINIMUM=Validierungsfehler\: Der Wert ist kleiner als das erlaubte Minimum von ''{0}'' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MAXIMUM=Validierungsfehler\: Der Wert ist gr\u00F6\u00DFer als das erlaubte Maximum von ''{0}'' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MINIMUM=Validation Error\: Der Wert ist kleiner als das erlaubte Minimum von ''{0}'' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=Validierungsfehler\: Der Wert ist nicht zwischen den erwarteten Werten von {0} und {1}. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.TYPE=Validierungsfehler\: Der Wert ist nicht vom korrekten Typ. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.NOT_IN_RANGE=Validierungsfehler\: Der Wert liegt nicht im erwarteten Wertebereich von {0} bis {1}. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.STRING=Konnte ''{0}'' nicht in eine Zeichenkette konvertieren. diff --git a/zanata-war/src/main/resources/messages_en_GB.properties b/zanata-war/src/main/resources/messages_en_GB.properties deleted file mode 100644 index ea62013e99..0000000000 --- a/zanata-war/src/main/resources/messages_en_GB.properties +++ /dev/null @@ -1,1103 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Zanata=Zanata -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Active=Active -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ReadOnly=Read-only -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Obsolete=Obsolete -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RecordNotFound=Record not found -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.DuplicatedRecord=Duplicated record -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AnotherUserChangedTheSameDataPleaseTryAgain=Another user changed the same data. Please try again. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.YouDoNotHavePermissionToAccessThisResource=You do not have permission to access this resource. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.YourSessionHasTimedOutPleaseTryAgain=Your session has timed out. Please try again. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Actions=Actions -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Add=Add -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Cancel=Cancel -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Close=Close -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CreationDate=Creation Date -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Delete=Delete -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Description=Description -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Edit=Edit -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Email=Email -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Help=Help -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.HomepageContent=Homepage Content -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Language=Language -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Name=Name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.projectType=Project Type -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.projectType.Description=Determines how the project is treated for upload and download by clients or through the website. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.projectType.DefaultBehaviour=The default type will be applied to versions under this project that do not specify their own type. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.projectType.NotSpecifiedBehaviour=If no project type is specified, the type from containing project is used. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.projectType.MoreInfo=For more information, see https\://github.com/zanata/zanata/wiki/Project-Types -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.projectType.NoSelection=-- No selection -- -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Remove=Remove -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Save=Save -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Search=Search -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Status=Status -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Update=Update -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Upload=Upload -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Username=Username -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Version=Version -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Projects=Projects -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Groups=Groups -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Languages=Languages -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.More=More -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ReportAProblem=Report problem -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.KnownIssues=Known issues -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary=Glossary -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Administration=Administration -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Register=Register -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.MyProfile=My Profile -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SearchProjects=Search Projects -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.search.IncludeObsoleteTooltip=Include Obsolete Projects in Search -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AboutZanata=About Zanata -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Documentation=Documentation -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Wiki=Wiki -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Blog=Blog -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Support=Support -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.IrcHelp=IRC Help -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.FAQ=FAQ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SiteMap=Site map -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RunningVersionInfo=\#{messages['jsf.Zanata']} version \#{applicationConfiguration.version} (\#{applicationConfiguration.buildTimestamp}). -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CopyrightNotice=&\#169; 2008-12 Red Hat, Inc and others. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Home=Home -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.server.EditHomePage.label=Edit Page Content -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.server.EditHomePageCode.label=Edit Page Code -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.server.EditHomePageCode.tooltip=Edit the home page code as persisted. Useful when the home page cannot be edited via the edit page. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EditHomePage=Edit Home Page -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CreateProject=Create project -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.FilterActiveProjects=Filter active projects -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.FilterReadOnlyProjects=Filter read-only projects -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.FilterObsoleteProjects=Filter obsolete projects -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ProjectName=Project Name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoProjectExists=No project exists. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SearchResultsForProjectSearch=Search Results for '\#{projectSearch.searchQuery}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.projectSearch.searchQuery.title=Found \#{projectSearch.resultSize} Projects matching query '\#{projectSearch.searchQuery}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.OnlyShowingFirstPagesizeResults=Only showing first \#{projectSearch.pageSize} results. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CreateANewProject=Create a New Project -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EditProject=Edit Project -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ProjectId=Project ID -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ProjectIdExample=Example\: my-project -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.viewSourceFiles=View source files -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.viewSourceFiles.Example=Link to human-readable source, e.g. https\://github.com/zanata/zanata -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SourceCheckoutUrl=Source Download/Checkout -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SourceCheckoutUrl.Example=URL for checkout of source by version control software, e.g. git@github.com\:zanata/zanata.git -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.customizedLocaleMessage=Would you like to add a customised list of locales? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.DisabledLocales=Disabled Locales -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EnabledLocales=Enabled Locales -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AddLocale=Add > -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RemoveLocale=< Remove -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RestrictRoleAccessMessage=Would you like to restrict access to this project to certain User roles? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RestrictRoleAccessTooltip=Restrict Project Access -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.customizedValidationMessage=Would you like to use a customised list of validations? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ProjectVersionId=Version ID -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ReadOnlyVersions=Read-only versions -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ObsoleteVersions=Obsolete versions -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.DocumentCount=Documents\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.TranslateLinks=Translate Links -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Translate=Translate -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.TranslateGWTDevMode=Translate (GWT DevMode) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Open=Open -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.OpenGWTDevMode=Open (GWT DevMode) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageVersion=Manage Version -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EditVersion=Edit Version -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SourceDocs=Source Docs -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SourceDocuments=Source Documents -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.EditHomePage.label=Edit Page Code -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.EditHomePage.tooltip=Edit the Project's home page code as persisted. Useful when the home page cannot be edited via the project edit page. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CreateVersion=Create Version -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageMaintainers=Manage Maintainers -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CopyTrans=Copy Trans -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.CopyTransOpts.tooltip=Set this project's default \#{messages['jsf.CopyTrans']} settings. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ProjectMaintainers=Project Maintainers -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoMaintainers=(No maintainers defined) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.RoleRestrictions=Role Restrictions -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.ProjectRestrictedToFollowingRoles=This project has restricted access for the following User roles\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AddProjectMaintainer=Add Project Maintainer -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AreYouSureYouWishToRemoveThisPersonAsProjectMaintainer=Are you sure you wish to remove this person as project maintainer? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AddGroupMaintainer=Add Group Maintainer -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AreYouSureYouWishToRemoveThisPersonAsGroupMaintainer=Are you sure you wish to remove this person as group maintainer? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.YouAreNoLongerMaintainerForThisProject=You are no longer a maintainer for this project. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.CopyTransOpts.title=\#{messages['jsf.CopyTrans']} Options -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.project.CopyTransOpts.saved=\#{messages['jsf.CopyTrans']} options saved. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.pageTitle=\#{messages['jsf.CopyTrans']} for \#{viewAllStatusAction.projectSlug}\:\#{viewAllStatusAction.iterationSlug} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Condition=Condition -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Condition.onContentMismatch=On Content mismatch\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Condition.onProjectMismatch=On Project mismatch\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Condition.onContextMismatch=On Context mismatch (resId, msgctxt)\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Condition.onDocIdMismatch=On Document Id mismatch (Document name and path)\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Condition.final=Otherwise\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Action=Action -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Help.downgradeToFuzzy=The translation is still considered for reuse, but it will be reused as fuzzy. Subsequent conditions will be checked. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Help.ignore=This condition will not be taken into account to determine whether a translation is reused or not. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Start=Start -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.AlreadyStarted=\#{messages['jsf.CopyTrans']} has already been started by \#{copyTransManager.getCopyTransProcessHandle( copyTransAction.projectIteration ).triggeredBy} for version \#{copyTransAction.projectIteration.slug} of project \#{copyTransAction.projectIteration.project.name}. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CopyTrans.ClickHereToViewProgress=Please click here to view progress. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.AlreadyStarted.flash=Someone else already started a \#{messages['jsf.CopyTrans']} for this version. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.NoDocuments=There are no documents in this project version. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.Started=\#{messages['jsf.CopyTrans']} started. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.ShowAllLocales.title=Your teams will be highlighted below. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Refresh=Refresh -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RefreshTable=Refresh table -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.stats.OpenInWebEditor=Open in Translation Editor -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Documents=Documents -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Statistics=Statistics -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ByWords=By Words -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Message=By Message -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.stats.Total=Total\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.stats.Translated=Translated\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.stats.ShortHoursSuffix=hrs -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoContent=(No Content) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.LastTranslated=Last Translated -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ConfigFile=Config file -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.GenerateProjectConfig=Generate project configuration file (zanata.xml) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans=Copy Translations -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.title=Copy approved translations from other similar documents. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.JoinedGroups=Joined Groups -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.inProgress=\#{messages['jsf.CopyTrans']} in progress... -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.started=Started \#{viewAllStatusAction.copyTransStartTime} ago by \#{pHandle.triggeredBy} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.CopyTrans.estimatedTimeRemaining=Estimated Time Remaining\: \#{viewAllStatusAction.copyTransEstimatedTimeLeft} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.group.FindGroup=Find Group -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoResultToDisplay=No result to display. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.GroupName=Group Name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SelectGroup=Select group -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Select=Select -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.pager.NextPage=next -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.pager.PreviousPage=prev -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.NoFiles=No Files Available -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.Path=Path -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.Filter.title=Filter by document name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Upload.Title=Upload document to merge/override current translation -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.UploadFile=Upload File -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.Merge=Merge -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.Merge.title=When checked, current data will merge with uploaded document. Otherwise data will be override by uploaded document. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.MergeCheckbox.Title=When checked, updated translations will be written, leaving all others unchanged. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.Download=Download -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotpot=.pot -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotofflinepot=offline .pot -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotofflinepot.description=Special pot format that uses msgctxt to store Zanata id. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotofflinepot.purpose=This is provided only for use during offline translation, source files should not be uploaded in this format. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotpo=.po -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotofflinepo=offline .po -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotofflinepo.description=Special po format that uses msgctxt to store Zanata Id. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.dotofflinepo.purpose=This format is required by Zanata when uploading po translations for a document that was originally in a non-po format. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.ConfirmDocDeletion=Are you sure you want to remove this Source Document? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DocumentDeleted=Document succesfully deleted. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.ProcessDlgTitle=Processing project files... -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.UploadDocument=Upload Document -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SupportedUploadFormats=Supported types\: .pot .dtd .txt .odt .fodt .odp .fodp .ods .fods .odg .fodg .odb .odf -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SourceLanguage=Source Language -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DocumentPath=Document Path -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ConfigFileForOfflineTranslation=Offline Translation Config File -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.GenerateProjectConfigSingleLocale=Generate project configuration file (zanata.xml) for this version with locale \#{projectIterationFilesAction.localeId} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.GenerateProjectConfigForOfflineTranslation=Generate project configuration file (zanata.xml) for this version with locale \#{projectIterationFilesAction.localeId}, using special project type 'offlinepo' for use in offline translation of po files. -jsf.ConfigFileDisabledProjectNotSet=Disabled because maintainer has not set project type for this project. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DownloadAllFiles=Download All Files (zip) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DownloadAllFiles.title=Download all translated files. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DownloadAllFilesOfflinePo=Download All Files (offline po zip) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DownloadAllFilesOfflinePo.title=Download all translated files in po format for offline translation. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed=The project type must be set to 'Gettext' or 'Podir'. Contact the project maintainer. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotSet=The project type for this iteration has not been set. Contact the project maintainer. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.ConfirmDownloadAllFiles=Your download will be prepared and may take a few minutes to complete. Is this ok? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.generatezip.ProgressLabel=\#{projectIterationZipFileAction.zipFilePrepHandle.currentProgress} of \#{projectIterationZipFileAction.zipFilePrepHandle.maxProgress} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.WhyCantITranslate=Why can't I translate? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.translateDenied.NotLoggedIn=You are not logged In. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.translateDenied.VersionIsReadOnly=This project version is Read-Only. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.translateDenied.VersionIsObsolete=This project version is Obsolete. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.iteration.files.translateDenied.UserNotInProjectRole=You must be part of these user roles to translate this project\: {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoGroupExists=No group exists. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.groups.ShowActiveGroups=Show active groups -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.groups.ShowObsoleteGroups=Show obsolete groups -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.GroupId=Group ID -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.GroupIdExample=Example\: my-group -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AddProjectVersions=Add Project Versions -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.groups.FindProjectVersion=Find Project Version -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoResultToDisplayProjectSearch=No results to display. Please check whether the desired project contains any versions. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.SelectAll=Select All -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AddSelected=Add Selected -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EditGroup=Edit Group -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.GroupMaintainers=Group Maintainers -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CreateSupportedLanguage=Add New Language -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NativeName=Native Name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Members=Members -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.LanguageTeamTitle=\#{languageTeamAction.locale.retrieveDisplayName()} Team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SizeMembers=\#{languageTeamAction.locale.members.size} members -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Coordinator=Coordinator -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.JoinLanguageTeam=Join Language Team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.LeaveLanguageTeam=Leave Language Team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RequestToJoinLanguageTeam=Request To Join Team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.contactLanguageTeamCoordinator=Contact Team Coordinators -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AddTeamMember=Add Team Member -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.FindUsersToAdd=Find Users To Add -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AlreadyInTeam=Already in Team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EditHelpPageContent=Edit Help Page Content -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ContactAdmin=Contact Admin -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Entries=Entries -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary.supportedFileFormat=Supported file format\: PO and CSV -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary.SourceLocale.Title=Source locale (only applies for PO file format) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.TargetLanguage=Target Language -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary.TargetLocale.Title=Target locale (only applies for PO file format) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary.TreatSourceCommentsAsTarget=Treat source comments and ref as target comments? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary.TreatSourceCommentsAsTarget.Title=When checked, source comments and references will be used as target comments -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary.CommentColumnNames=Comment column names -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Glossary.CommentColumnNames.Title=Customised comment column headers for csv file format. Format of CSV\: {source locale},{locale1},{locale2},...,{pos},{description} OR {source locale},{locale},{locale},...,{description1},{description2},... (only applies for CSV file format) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ThisActionCannotBeUndone=This action cannot be undone -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SelectLocaleToDelete=Select locale to delete -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SignUp=Sign Up -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NameToolTip=The name should be first letter capitalised. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EmailToolTip=The email should be in username@domain.name format. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.UsernameToolTip=The username should be all in lower case. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Password=Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ConfirmPassword=Confirm Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.IAgreeToThe=I agree to the -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.TermsOfUse=Terms of Use -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.register.LoginUsingOpenId=You can also login using Open Id Here. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.PleaseContactAdministrationToGetRegistrationLink=Please contact administration to get registration link. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ForgotYourPassword=Forgot your password? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ResetPassword=Reset Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SubmitRequest=Submit Request -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ResetYourPassword=Reset Your Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NewPassword=New Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.OldPassword=Old Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ChangePassword=Change Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RememberMe=Remember me -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.login.openid.SelectProvider=How are you logging in? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.login.openid.fedora=Fedora Username -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.login.openid.myopenid=MyOpenID User -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.login.openid.yahoo=Yahoo Username -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.login.openid=Open ID -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.login.internal=Username -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.UsernameNotAvailable=Username "\#{userAction.username}" is not available -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.FedoraUsername=Fedora Username -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ActivateAccount=Activate Account -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ValidateEmail=Validate Email -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.InactiveAccount=Inactive account -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.inactiveaccount.PleaseSelectOne=Your account has not yet been activated. Please select one of the following options\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ResendActivationEmail=Re-send activation email -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.or=OR -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.inactiveaccount.UpdateAndResend=Update email address and re-send activation email\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.UpdateEmail=Update email address -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.InvalidActivationKey=Invalid activation key -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ActivationLinkExpired=Activation link expired. Please sign in and click "\#{messages['jsf.ResendActivationEmail']}". -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Error=Error -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ErrorTitle=Current Errors\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoErrors=No errors -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EditProfile=Edit Profile -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageIdentities=Manage Identities -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.MergeAccount=Merge Account -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.MergeAccount.tootip=Use this if you wish to merge two Zanata accounts into a single one. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ApiKey=API Key -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.YourCurrentApiKeyIs=Your current API key is -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NotGenerated=(Not generated) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.apikey.ConfirmGenerate=Are you sure you want to generate your API Key? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ConfigurationForZanataini=Configuration [zanata.ini] -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.MaintainedProjects=Maintained Projects -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.LanguageTeams=Language Teams -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.MaintainedGroups=Maintained Groups -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.FirstExternalLoginMessage=Please verify the email address below and click Save to validate your email address. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AccountDetails=Account Details -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.Title=Identities -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.ConfirmIdentityRemoval=Are you sure you want to remove this Identity? You will not be able to Sign In using this identity. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.Type=Type -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.User=Identity -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.AddIdentity=Add New Identity -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.identities.Verify=Verify Identity -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.profile.MergeAccount=Merge Accounts -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.profile.MergeAccount.info=Log in to the account you want to merge. You will need to use one of the authentication methods offered below. You will be asked for further confirmation after this. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.profile.MergeAccount.confirm=Do It -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.profile.MergeAccount.confirmationMessage=You are about to merge in the following account\:

Username\: \#{accountMergeAction.obsoleteAccount.username}
Name\: \#{accountMergeAction.obsoleteAccount.person.name}
Email\: \#{accountMergeAction.obsoleteAccount.person.email}

This change is permanent and cannot be taken back.

The account mentioned above will be inactivated and all of its permissions revoked. Your current account will inherit all these permissions.

Are you sure you want to do this? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ServerConfiguration=Server Configuration -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageUsers=Manage Users -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageRoles=Manage Roles -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageLanguage=Manage Languages -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch=Manage Search -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.OverallStatistics=Overall Statistics -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RoleAssignmentRules=Role Assignment Rules -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ServerMonitoring=Server Monitoring -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ProcessManager=Process Manager -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ServerUrl=Server URL -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.UrlToolTip=The base URL for the server, including the application context path (no final slash) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.UrlExample=e.g. http\://example.com/zanata or http\://zanata.example.com -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RegisterUrl=Register URL -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RegisterUrlToolTip=The user registration URL for the server -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RegisterUrlExample=e.g. /zanata/account/register or http\://example.com/register -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EmailDomainName=Email Domain Name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EmailDomainNameToolTip=Email Domain Name should be in example.com format. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EmailDomainNameExample=e.g. redhat.com -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.AdminEmail=Contact Admin Address -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.AdminEmail.tooltip=Email will be sent to these addresses when the 'Contact Admin' form is used. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.AdminEmail.DoesNotChangeUserEmail=This field does not change the individual email address for any admin users. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.EmailListToolTip=Email addresses should be separated by a single comma (,) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.FromEmailAddr=From Email Address -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.FromEmailAddr.tooltip=This will be used in the 'from' field of any emails sent by this zanata server -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.EnableLogEmails=Enable Log emails -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.EnableLogEmails.tooltip=Enables or disables the sending of Zanata diagnostics log information via email. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.LogDestEmail=Log Destination email addresses -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.LogDestEmail.tooltip=Email will be sent to these addresses when a logging event occurs. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.LogEmailLevel=Email log level -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.LogEmailLevel.tooltip=Log level to send via email. i.e. Error will only send error messages, while Warning will send both warning and error messages. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Warning=Warning -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.PiwikUrl=Piwik URL -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.Piwiktooltip=Piwik analytic tools URL. i.e. http\://localhost/piwik -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.PiwikIdSite=Piwik Id -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.config.PiwikIdSitetooltip=Website Id in Piwik -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CreateNewUser=Create new user -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.MemberOf=Member of -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Enabled=Enabled -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AreYouSureYouWishToDeleteThisUserThisActionCannotBeUndone=Are you sure you wish to delete this user? This action cannot be undone. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.UserManager.delete.constraintViolation.error=This user cannot be removed from the system. You can deactivate the user instead. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AccountEnabled=Account enabled -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CreateRole=Create Role -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AreYouSureYouWishToDeleteThisRoleThisActionCannotBeUndone=Are you sure you wish to delete this role? This action cannot be undone. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Role=Role -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RoleDetails=Role Details -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.EnabledByDefault=Enabled by default -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AreYouSureYouWishToDeleteThisLanguageThisActionCannotBeUndone=Are you sure you wish to delete this language? This action cannot be undone. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AreYouSureYouWishToEnableThisLanguage=Are you sure you wish to enable this language? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AreYouSureYouWishToDisableThisLanguage=Are you sure you wish to disable this language? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.manager.DisableByDefaultConfirmation=Are you sure you wish to Disable this language by default? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.manager.EnableByDefaultConfirmation=Are you sure you wish to Enable this language by default? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.TeamMembers=Team Members -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.validation.ReplaceUnderscores=Replace them. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.validation.Underscores=Underscores should be replaced with dashes. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.CountryCode=Country Code -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.LanguageCode=Language Code -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Variant=Variant -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.validation.Invalid=Invalid Language Name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.validation.Existing=This language already exists -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.validation.UnknownPluralForm=Warning\: No plural information available. Assuming no plurals. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.language.validation.SimilarLocaleFound=Similar languages found\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.AllActions=(all actions) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.Table=Table -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.AllTables=(all tables) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.purge=Purge index -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.purge.Description=Mark all existing index entries for the table obsolete. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.purge.ObsoletesOccupyDiskSpace=Obsolete entries still occupy disk space but are not returned in any searches. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.purge.RemoveByRunningOptimize=Obsolete entries can be completely removed by running Optimise any time after Purge. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.reindex=Reindex -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.reindex.Description=Index all rows in the given table. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.reindex.OnlyWhenOutOfDate=Rows will be indexed automatically when data is persisted, so this operation is only necessary when the index is out-of-date (e.g. when the database has been restored from backup, after a failed reindex, if index files have been removed). -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.reindex.AllRowsWillBeReindexed=All rows of the given table will be reindexed regardless whether they already have an entry in the index. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.reindex.IndexedRowsWillBeUpdated=Rows that have already been indexed will have their entries updated, which will usually have no effect on the entry. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.reindex.TimeAndMemoryWarning=Warning\: this operation can take hours for large tables, and will increase memory use significantly above baseline. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.reindex.RunDuringOffPeak=It is strongly recommended to run this operation during off-peak times when average server memory use is at a minimum. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.optimize=Optimise -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.optimize.Description=Arrange index entries to maximize search speed. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.optimize.RemovesObsoleteEntries=Also removes any obsolete entries from the index. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.optimize.WillNotInfluenceIndexTime=Will not influence indexing time. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.optimize.TempFileWarning=Warning\: this operation uses a temp file that will require free disk space of approximately the current index size. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.SelectNone=Clear Selection -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.PerformSelectedActions=Perform Selected Actions -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.CurrentProgress=Current Progress -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.NoOperationsRunning=No operations are running -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.Completed=Completed successfully (ran for \#{reindexAction.elapsedTime}) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.Aborted=Aborted by user (ran for \#{reindexAction.elapsedTime}) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.ErrorMessage=Due to an error, some objects could not be reindexed. See server log for details. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.PleaseReindex=Please reindex again to ensure the search index is up-to-date. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.ProgressMessage=\#{reindexAction.reindexProgress} of \#{reindexAction.reindexCount} operations complete -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.manageSearch.CurrentTable=Processing table\: \#{reindexAction.currentClass} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.ElapsedTime=Running for\: \#{reindexAction.elapsedTime} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.RemainingTime=Remaining (approx)\: \#{reindexAction.estimatedTimeRemaining} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ManageSearch.Abort=Abort -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Untranslated=Untranslated -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.CreateRule=New Rule -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.CreateRoleAssignmentRule=Create Role Assignment Rule -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.EditRoleAssignmentRule=Edit Role Assignment Rule -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.ConfirmDelete=Are you sure you want to remove this rule? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.Description=Role Assignment Rules assist with the automatic assignment of user roles to certain users when they sign in. If the user's identity (e.g. user name) matches a certain pattern and they are authenticated in a certain way (e.g. via Open Id where available), Zanata will be able to automatically add the user to a specified user Role. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.PolicyName=Policy Name -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.PolicyName.tooltip=This is the authentication policy used by a user to authenticate. If left unselected, it will apply to all policies. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.IdentityPattern=Identity Pattern -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.IdentityPattern.tooltip=Regular Expression to determine if this rule applies to a user Id. Note that the user Id varies depending on the authentication mechanism. If this value is left empty, the rule will apply to ALL user Ids. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.RoleToAssign=Role to Assign -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.rolerules.RoleToAssign.tooltip=This is the role that will be automatically assigned to the user upon login, only if the rule conditions are met. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.TotalRunning=Total Running -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.TotalFinished=Total Finished -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.Type=Type -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.status.Stopped=Stopped -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.status.Running=Running -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.status.WaitingToStop=Waiting to Stop -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.Progress=Progress -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.StartTime=Started -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.FinishTime=Finished -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.processmanager.Duration=Duration -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.From=From -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.ReplyAddress=Reply to -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.ReplyAddress.description=(your email address) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.Subject=Subject -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AdditionalInfo=Additional information -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.MessageBody=Message -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.Send=Send Message -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoProjects=No projects to display. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.SelectProjectVersions=Select Project Versions -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.NoProjectVersionSelected=No project version selected. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ClickSendMessageToProceedRequest=Enter additional information and click 'Send Message' to proceed -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.JoinGroupRequest.Subject=Request to join group '\#{versionGroupJoinAction.groupName}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RequestAddProjectToGroup=Request To Join Group -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.AlreadyInGroup=Already in Group -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.joingrouprequest.AdditionalInfoMessage=To ensure your request is processed without delay, please provide any additional information that will help the group maintainers to process your request. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.RequestToJoinLanguageTeamTitle=Request To Join '\#{sendEmail.locale.localeId.id}' Language Team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.joinrequest.Subject=User '\#{sendEmail.fromLoginName}' wants to join the '\#{sendEmail.locale.localeId.id}' language team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.ContactCoordinatorTitle=Contact '\#{sendEmail.locale.retrieveDisplayName()}' Coordinator -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.contactLanguageTeamCoordinatorForLocale=Contact '\#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()})' Language Team Coordinators -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.YouAreReceivingThisMailBecause=You are receiving this mail because\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.GeneratedFromZanataServerAt=This message generated by Zanata running at\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.Account.ActivationMessage=You will soon receive an email with a link to activate your account. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.activation.Subject=Zanata Account Activation -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.activation.register.DearName=Dear \#{emailServiceImpl.toName}, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.activation.profile.DearName=Dear \#{profileAction.name}, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.activation.ClickLinkToActivateAccount=Please click on the following link to activate your account\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.activation.Link=Account activation link -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.alternate.copyPasteMessage=Alternately, you can copy and paste the following URL into your browser\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.UrlExpireMessage=URL will expire after 24 hours. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.accountchange.Subject=Zanata Email Change Confirmation -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.accountchange.DearName=Dear \#{profileAction.name}, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.accountchange.Message=Zanata has received a request to update your email to \#{profileAction.email} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.accountchange.Message2=If you did not request this action or are unsure about why it was done, please contact the Zanata System administrators as soon as possible. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.accountchange.ConfirmationLink=Click here to confirm email change -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.usernamechange.Subject=Your Zanata username has been changed. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.usernamechange.DearName=Dear \#{userAction.getName(userAction.username)}, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.usernamechange.Content=Your Zanata username has been recently changed by one of the System Administrators. If you did not request this action or are unsure about why it was done, please contact the Zanata System administrators as soon as possible. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.usernamechange.YourNewUsername=Your new username is '\#{userAction.username}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.usernamechange.ResetPassword=You now need to reset your password. To do this, please click on the link below\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.usernamechange.ClickLinkForPasswordReset=Click Here to Reset Your Password -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.passwordreset.Subject=Zanata Reset Password Request -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.passwordreset.DearName=Dear \#{passwordResetRequest.account.person.name}, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.passwordreset.FollowLinkToResetPassword=Please follow the link below to reset the password for your account. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.passwordreset.IgnoreIfNotRequested=If you haven't explicitly requested a password reset, you can ignore this request. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.admin.SentNotification=Your message has been sent to the administrator -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.admin.SubjectPrefix=Zanata user email from '\#{sendEmail.fromLoginName}'\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.ZanataAdministrator=Zanata Administrator -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.admin.DearAdmin=Dear Administrator, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.admin.UserMessageIntro=Zanata user '\#{sendEmail.fromName}' with Id '\#{sendEmail.fromLoginName}' has sent the following message\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.ReplyInstructions=You can reply to \#{sendEmail.fromName} at \#{sendEmail.replyEmail} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.admin.ReceivedReason=You are an administrator in the system configuration -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.admin.user.ReceivedReason=You are an administrator -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.coordinator.SentNotification=Your message has been sent to the \#{sendEmail.locale.retrieveNativeName()} language team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.coordinator.SubjectPrefix=Zanata\: \#{sendEmail.locale.localeId.id} Language Team\: message from '\#{sendEmail.fromLoginName}'\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.coordinator.DearCoordinator=Dear Language Team Coordinator, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.coordinator.UserMessageIntro=Zanata user '\#{sendEmail.fromName}' with id '\#{sendEmail.fromLoginName}' has sent the following message to the \#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()}) Language Team\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.coordinator.ResponseInstructions=You can click the link below to go directly to the \#{sendEmail.locale.localeId.id} Language Team Page. Please reply to \#{sendEmail.fromName} at \#{sendEmail.replyEmail} when you have finished processing their request. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.coordinator.ReceivedReason=You are coordinator in '\#{sendEmail.locale.retrieveNativeName()}' language team -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.group.maintainer.SentNotification=Your message has been sent to the \#{versionGroupJoinAction.groupName} group maintainer -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.maintainer.DearMaintainer=Dear Group Maintainer, -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.joingrouprequest.RequestingToJoinGroup=Zanata user '\#{sendEmail.fromName}' with Id '\#{sendEmail.fromLoginName}' is requesting his/her project(s) to be added to group '\#{versionGroupJoinAction.groupName}'. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.JoinGroupRequest.ResponseInstructions=Click the link below to go act on the request. Please reply to \#{sendEmail.fromName} at \#{sendEmail.replyEmail} when you have finished processing their request. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -jsf.email.group.maintainer.ReceivedReason=You are maintainer in group '\#{versionGroupJoinAction.groupName}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -up=\u2191 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -down=\u2193 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -left=\u2039 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -right=\u203A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.loginFailed=Login failed -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.loginSuccessful=Welcome, \#0\! -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.NotLoggedIn=Please log in first -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.TransactionFailed=Transaction failed -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.NoConversation=The conversation ended, timed out or was processing another request -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.IllegalNavigation=Illegal navigation -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.ProcessEnded=Process \#0 already ended -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.ProcessNotFound=Process \#0 not found -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.TaskEnded=Task \#0 already ended -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -org.jboss.seam.TaskNotFound=Task \#0 not found -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.component.UIInput.CONVERSION=value could not be converted to the expected type -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.component.UIInput.REQUIRED=value is required -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.component.UIInput.UPDATE=an error occurred when processing your submitted information -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.component.UISelectOne.INVALID=value is not valid -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.component.UISelectMany.INVALID=value is not valid -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.BigDecimalConverter.DECIMAL=value must be a number -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=value must be a signed decimal number consisting of zero or more digits, optionally followed by a decimal point and fraction, eg. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.BigIntegerConverter.BIGINTEGER=value must be an integer -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=value must be a signed integer number consisting of zero or more digits -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.BooleanConverter.BOOLEAN=value must be true or false -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.BooleanConverter.BOOLEAN_detail=value must be true or false (any value other than true will evaluate to false) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.ByteConverter.BYTE=value must be a number between 0 and 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.ByteConverter.BYTE_detail=value must be a number between 0 and 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.CharacterConverter.CHARACTER=value must be a character -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.CharacterConverter.CHARACTER_detail=value must be a valid ASCII character -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DateTimeConverter.DATE=value must be a date -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DateTimeConverter.DATE_detail=value must be a date, eg. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DateTimeConverter.TIME=value must be a time -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DateTimeConverter.TIME_detail=value must be a time, eg. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DateTimeConverter.DATETIME=value must be a date and time -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DateTimeConverter.DATETIME_detail=value must be a date and time, eg. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=a pattern or type attribute must be specified to convert the value -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DoubleConverter.DOUBLE=value must be a number -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.DoubleConverter.DOUBLE_detail=value must be a number between 4.9E-324 and 1.7976931348623157E308 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.EnumConverter.ENUM=value must be convertible to an enum -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.EnumConverter.ENUM_detail=value must be convertible to an enum or from the enum that contains the constant {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=value must be convertible to an enum or from the enum, but no enum class provided -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=value must be convertible to an enum or from the enum, but no enum class provided -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.FloatConverter.FLOAT=value must be a number -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.FloatConverter.FLOAT_detail=value must be a number between 1.4E-45 and 3.4028235E38 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.IntegerConverter.INTEGER=value must be an integer -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.IntegerConverter.INTEGER_detail=value must be an integer number between -2147483648 and 2147483647 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.LongConverter.LONG=value must be an integer -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.LongConverter.LONG_detail=value must be an integer number between -9223372036854775808 and 9223372036854775807 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.CURRENCY=value must be a currency amount -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.CURRENCY_detail=value must be a currency amount, eg. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.PERCENT=value must be a percentage amount -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.PERCENT_detail=value must be a percentage amount, eg. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.NUMBER=value must be a number -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.NUMBER_detail=value must be a number -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.PATTERN=value must be a number -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.NumberConverter.PATTERN_detail=value must be a number -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.ShortConverter.SHORT=value must be an integer -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.ShortConverter.SHORT_detail=value must be an integer number between -32768 and 32767 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.DoubleRangeValidator.MAXIMUM=value must be less than or equal to {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.DoubleRangeValidator.MINIMUM=value must be greater than or equal to {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=value must be between {0} and {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.DoubleRangeValidator.TYPE=value is not of the correct type -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.LengthValidator.MAXIMUM=value must be shorter than or equal to {0} characters -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.LengthValidator.MINIMUM=value must be longer than or equal to {0} characters -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.LongRangeValidator.MAXIMUM=value must be less than or equal to {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.LongRangeValidator.MINIMUM=value must be greater than or equal to {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=value must be between {0} and {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.LongRangeValidator.TYPE=value is not of the correct type -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.validator.NOT_IN_RANGE=value must be between {0} and {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author irooskov -javax.faces.converter.STRING=value could not be converted to a string diff --git a/zanata-war/src/main/resources/messages_fr.properties b/zanata-war/src/main/resources/messages_fr.properties deleted file mode 100644 index d37e9a10fb..0000000000 --- a/zanata-war/src/main/resources/messages_fr.properties +++ /dev/null @@ -1,140 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -up=\u2191 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -down=\u2193 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -left=\u2039 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -right=\u203A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginFailed=La connexion a \u00EF\u00BF\u00BDchou\u00EF\u00BF\u00BD. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginSuccessful=Bienvenue, {0}\! -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NotLoggedIn=Veuillez d'abord vous connecter. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TransactionFailed=La transaction a \u00EF\u00BF\u00BDchou\u00EF\u00BF\u00BD. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NoConversation=La conversation s'est interrompue, a d\u00EF\u00BF\u00BDpass\u00EF\u00BF\u00BD les d\u00EF\u00BF\u00BDlais ou traite une autre requ\u00EF\u00BF\u00BDte. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.IllegalNavigation=Navigation ill\u00EF\u00BF\u00BDgale -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessEnded=Processus \#0 d\u00EF\u00BF\u00BDj\u00EF\u00BF\u00BD achev\u00EF\u00BF\u00BD -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessNotFound=Le processus \#0 n'a pas \u00EF\u00BF\u00BDt\u00EF\u00BF\u00BD trouv\u00EF\u00BF\u00BD. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskEnded=T\u00EF\u00BF\u00BDche \#0 d\u00EF\u00BF\u00BDj\u00EF\u00BF\u00BD achev\u00EF\u00BF\u00BDe -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskNotFound=La t\u00EF\u00BF\u00BDche \#0 n'a pas \u00EF\u00BF\u00BDt\u00EF\u00BF\u00BD trouv\u00EF\u00BF\u00BDe. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.CONVERSION=La valeur ne peut \u00EF\u00BF\u00BDtre convertie dans le type attendu -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.REQUIRED=Une valeur est requise. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.UPDATE=Une erreur est survenue lors du traitement de l'information que vous avez fournie -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectOne.INVALID=La valeur n'est pas valide. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectMany.INVALID=La valeur n'est pas valide. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre d\u00EF\u00BF\u00BDcimal sign\u00EF\u00BF\u00BD comprenant z\u00EF\u00BF\u00BDro chiffre ou plus, \u00EF\u00BF\u00BDventuellement suivi par une virgule d\u00EF\u00BF\u00BDcimale et une faction, par ex. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=la valeur doit \u00EF\u00BF\u00BDtre un entier sign\u00EF\u00BF\u00BD comprenant z\u00EF\u00BF\u00BDro chiffre ou plus -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN=la valeur doit \u00EF\u00BF\u00BDtre "vrai" ou "faux" -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN_detail=la valeur doit \u00EF\u00BF\u00BDtre "vrai" ou "faux" (toute valeur autre que "vrai" est \u00EF\u00BF\u00BDvalu\u00EF\u00BF\u00BDe \u00EF\u00BF\u00BD "faux") -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE=la valeur doit \u00EF\u00BF\u00BDtre un nombre entre 0 et 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre entre 0 et 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER=la valeur doit \u00EF\u00BF\u00BDtre un caract\u00EF\u00BF\u00BDre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER_detail=la valeur doit \u00EF\u00BF\u00BDtre un caract\u00EF\u00BF\u00BDre ASCII valide -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE=la valeur doit \u00EF\u00BF\u00BDtre une date -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE_detail=la valeur doit \u00EF\u00BF\u00BDtre une date, par ex. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME=la valeur doit \u00EF\u00BF\u00BDtre une heure -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME_detail=la valeur doit \u00EF\u00BF\u00BDtre une heure, par ex. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME=la valeur doit \u00EF\u00BF\u00BDtre une date et une heure -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME_detail=la valeur doit \u00EF\u00BF\u00BDtre une date et une heure, par ex. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=un attribut doit indiquer le mod\u00EF\u00BF\u00BDle ou le type pour convertir la valeur -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre entre 4,9E-324 et 17976931348623157E308 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM=la valeur doit \u00EF\u00BF\u00BDtre convertible en une \u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_detail=la valeur doit \u00EF\u00BF\u00BDtre convertible en une \u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration ou depuis l''\u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration qui contient la constante {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=la valeur doit \u00EF\u00BF\u00BDtre convertible en une \u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration ou depuis l'\u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration, mais aucune classe d'\u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration n'est fournie -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=la valeur doit \u00EF\u00BF\u00BDtre convertible en une \u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration ou depuis l'\u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration, mais aucune classe d'\u00EF\u00BF\u00BDnum\u00EF\u00BF\u00BDration n'est fournie -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre entre 1,4E-45 et 3,4028235E38 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre entre -2147483648 et 2147483647 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre entre -9223372036854775808 et 9223372036854775807 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY=la valeur doit \u00EF\u00BF\u00BDtre un montant mon\u00EF\u00BF\u00BDtaire -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY_detail=la valeur doit \u00EF\u00BF\u00BDtre un montant mon\u00EF\u00BF\u00BDtaire, par ex. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT=la valeur doit \u00EF\u00BF\u00BDtre un pourcentage -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT_detail=la valeur doit \u00EF\u00BF\u00BDtre un pourcentage, par ex. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN_detail=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT=la valeur doit \u00EF\u00BF\u00BDtre un nombre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT_detail=la valeur doit \u00EF\u00BF\u00BDtre comprise entre -32768 et 32767 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MAXIMUM=La valeur doit \u00EF\u00BF\u00BDtre inf\u00EF\u00BF\u00BDrieure ou \u00EF\u00BF\u00BDgale \u00EF\u00BF\u00BD {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MINIMUM=La valeur doit \u00EF\u00BF\u00BDtre sup\u00EF\u00BF\u00BDrieure ou \u00EF\u00BF\u00BDgale \u00EF\u00BF\u00BD {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=La valeur doit \u00EF\u00BF\u00BDtre comprise entre {0} et {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.TYPE=La valeur n'est pas du type correct -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MAXIMUM=La valeur doit comporter {0} caract\u00EF\u00BF\u00BDres ou moins -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MINIMUM=La valeur doit comporter {0} caract\u00EF\u00BF\u00BDres ou plus -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MAXIMUM=La valeur doit \u00EF\u00BF\u00BDtre inf\u00EF\u00BF\u00BDrieure ou \u00EF\u00BF\u00BDgale \u00EF\u00BF\u00BD {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MINIMUM=La valeur doit \u00EF\u00BF\u00BDtre sup\u00EF\u00BF\u00BDrieure ou \u00EF\u00BF\u00BDgale \u00EF\u00BF\u00BD {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=La valeur doit \u00EF\u00BF\u00BDtre comprise entre {0} et {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.TYPE=La valeur n'est pas du type correct -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.NOT_IN_RANGE=La valeur doit \u00EF\u00BF\u00BDtre comprise entre {0} et {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.STRING=La valeur ne peut \u00EF\u00BF\u00BDtre convertie en cha\u00EF\u00BF\u00BDne de caract\u00EF\u00BF\u00BDres diff --git a/zanata-war/src/main/resources/messages_gu.properties b/zanata-war/src/main/resources/messages_gu.properties deleted file mode 100644 index a03aa61772..0000000000 --- a/zanata-war/src/main/resources/messages_gu.properties +++ /dev/null @@ -1,32 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Zanata=Zanata -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Active=\u0AB8\u0A95\u0ACD\u0AB0\u0ABF\u0AAF -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.ReadOnly=\u0AAE\u0ABE\u0AA4\u0ACD\u0AB0-\u0AB5\u0ABE\u0A82\u0A9A\u0AC0 \u0AB6\u0A95\u0ABE\u0AAF -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Obsolete=\u0A9C\u0AC2\u0AA8\u0AC1\u0A82 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.RecordNotFound=\u0AB0\u0AC5\u0A95\u0ACB\u0AB0\u0ACD\u0AA1 \u0AAE\u0AB3\u0ACD\u0AAF\u0ACB \u0AA8\u0AB9\u0ABF -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.DuplicatedRecord=\u0AA8\u0A95\u0AB2\u0AC0 \u0AB0\u0AC5\u0A95\u0ACB\u0AB0\u0ACD\u0AA1 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Actions=\u0A95\u0ACD\u0AB0\u0ABF\u0AAF\u0ABE\u0A93 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Add=\u0A89\u0AAE\u0AC7\u0AB0\u0ACB -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Cancel=\u0AB0\u0AA6 \u0A95\u0AB0\u0ACB -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Close=\u0AAC\u0A82\u0AA7 \u0A95\u0AB0\u0ACB -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.CreationDate=\u0AAC\u0AA8\u0ABE\u0AB5\u0A9F \u0AA4\u0ABE\u0AB0\u0AC0\u0A96 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Delete=\u0A95\u0ABE\u0AA2\u0AC0 \u0AA8\u0ABE\u0A82\u0A96\u0ACB -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Description=\u0AB5\u0AB0\u0ACD\u0AA3\u0AA8 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Edit=\u0AAB\u0AC7\u0AB0\u0AAB\u0ABE\u0AB0 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Email=\u0A87\u0AAE\u0AC7\u0AB2 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Ankit Patel -jsf.Help=\u0AAE\u0AA6\u0AA6 diff --git a/zanata-war/src/main/resources/messages_it.properties b/zanata-war/src/main/resources/messages_it.properties deleted file mode 100644 index 5c82a07520..0000000000 --- a/zanata-war/src/main/resources/messages_it.properties +++ /dev/null @@ -1,140 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -up=\u2191 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -down=\u2193 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -left=\u2039 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -right=\u203A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginFailed=Autenticazione fallita -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginSuccessful=Benvenuto/a, \#0 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NotLoggedIn=Per favore, eseguire la login -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TransactionFailed=Transazione fallita -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NoConversation=La conversazione \u00E8 terminata, scaduta oppure \u00E8 stata processata un'altra richiesta -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.IllegalNavigation=Navigazione illegale -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessEnded=Il processo \#0 \u00E8 gi\u00E0\u00A0 terminato -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessNotFound=Il processo \#0 non \u00E8 stato trovato -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskEnded=Il task \#0 \u00E8 gi\u00E0 terminato -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskNotFound=Il task \#0 non \u00E8 stato trovato -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.CONVERSION=il valore non pu\u00F2 essere convertito -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.REQUIRED=\u00C8 richiesto un valore -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.UPDATE=Si \u00E8 verificato un errore nell'elaborazione delle informazioni inviate -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectOne.INVALID=il valore non \u00E8 valido -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectMany.INVALID=il valore non \u00E8 valido -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL=il valore deve essere un numero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=il valore deve essere un numero decimale con zero o pi\u00F9 cifre, opzionalmente seguito da un punto e una frazione, es. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER=deve essere un intero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=il valore deve essere un numero intero con zero o pi\u00F9 cifre -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN=deve essere vero o falso -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN_detail=il valore deve essere vero o falso (qualsiasi valore diverso da vero \u00E8 considerato falso) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE=il valore deve essere un numero compreso tra 0 e 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE_detail=il valore deve essere un numero compreso tra 0 e 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER=deve essere un carattere -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER_detail=il valore deve essere un carattere ASCII valido -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE=deve essere una data -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE_detail=il valore deve essere una data, es. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME=deve essere un orario -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME_detail=il valore deve essere un orario, es. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME=deve essere una data ed un orario -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME_detail=il valore deve essere una data e un orario, es. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=per convetire il valore devono essere specificati un pattern o un attributo tipo -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE=deve essere un numero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE_detail=il valore deve essere un numero compreso tra 4.9E-324 e 1.7976931348623157E308 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM=il valore deve essere convertibile in una enum -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_detail=il valore deve essere convertibile in una enum o da enum che contiene la costante {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=il valore deve essere convertibile in una enum o da enum, ma non \u00E8 stata fornita nessuna classe enum -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=il valore deve essere convertibile in una enum o da enum, ma non \u00E8 stata fornita nessuna classe enum -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT=deve essere un numero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT_detail=il valore deve essere un numero compreso tra 1.4E-45 e 3.4028235E38 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER=deve essere un numero intero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER_detail=il valore deve essere un numero intero compreso tra -2147483648 e 2147483647 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG=deve essere un numero intero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG_detail=il valore deve essere un numero intero compreso tra -9223372036854775808 e 9223372036854775807 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY=il valore deve essere una valuta -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY_detail=il valore deve essere una valuta, es. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT=il valore deve essere una percentuale -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT_detail=il valore deve essere una percentuale, es. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER=deve essere un numero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER_detail=deve essere un numero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN=deve essere un numero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN_detail=deve essere un numero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT=deve essere un numero intero -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT_detail=il valore deve essere un numero intero compreso -32768 e 32767 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MAXIMUM=il valore deve essere minore o uguale a {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MINIMUM=il valore deve essere maggiore o uguale a {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=il valore deve essere compreso tra {0} e {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.TYPE=il valore non \u00E8 del tipo corretto -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MAXIMUM=il valore deve essere inferiore o uguale {0} caratteri -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MINIMUM=il valore deve essere superiore o uguale {0} caratteri -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MAXIMUM=il valore deve essere minore o uguale a {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MINIMUM=il valore deve essere superiore o uguale a {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=il valore deve essere compreso tra {0} e {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.TYPE=il valore non \u00E8 del tipo corretto -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.NOT_IN_RANGE=il valore deve essere compreso tra {0} e {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.STRING=il valore non pu\u00F2 essere convertito a stringa diff --git a/zanata-war/src/main/resources/messages_ja.properties b/zanata-war/src/main/resources/messages_ja.properties deleted file mode 100644 index 78a66681f8..0000000000 --- a/zanata-war/src/main/resources/messages_ja.properties +++ /dev/null @@ -1,622 +0,0 @@ -jsf.Zanata=Zanata -# translation auto-copied from project oVirt Engine dwh, version master, document enum-translator, author ykatabam -jsf.Active=\u30A2\u30AF\u30C6\u30A3\u30D6 -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.ReadOnly=\u8AAD\u307F\u53D6\u308A\u5C02\u7528 -jsf.Obsolete=\u65E7\u7248 -jsf.RecordNotFound=\u8A18\u9332\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 -jsf.DuplicatedRecord=\u91CD\u8907\u8A18\u9332 -jsf.AnotherUserChangedTheSameDataPleaseTryAgain=\u540C\u3058\u30C7\u30FC\u30BF\u304C\u5225\u306E\u30E6\u30FC\u30B6\u30FC\u306B\u3088\u308A\u5909\u66F4\u3055\u308C\u307E\u3057\u305F\u3002 \u3084\u308A\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.YouDoNotHavePermissionToAccessThisResource=\u3053\u306E\u30EA\u30BD\u30FC\u30B9\u3078\u306E\u30A2\u30AF\u30BB\u30B9\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -jsf.YourSessionHasTimedOutPleaseTryAgain=\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u3066\u3044\u307E\u3059\u3002 \u3084\u308A\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.Actions=\u52D5\u4F5C -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Add=\u8FFD\u52A0 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.userportal.ApplicationConstants, author nnakakit -jsf.Cancel=\u53D6\u308A\u6D88\u3057 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Close=\u9589\u3058\u308B -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.CreationDate=\u4F5C\u6210\u65E5 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/uicompat/src/main/resources/org/ovirt/engine/ui/uicompat/LocalizedEnums, author nnakakit -jsf.Delete=\u524A\u9664 -# translation auto-copied from project oVirt, version master, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author ykatabam -jsf.Description=\u8A73\u7D30 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Edit=\u7DE8\u96C6 -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.Email=\u30E1\u30FC\u30EB -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.Help=\u30D8\u30EB\u30D7 -jsf.HomepageContent=\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8\u306E\u5185\u5BB9 -# translation auto-copied from project Fedora Installation Guide, version f18, document Kickstart2 -jsf.Language=\u8A00\u8A9E -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Name=\u540D\u524D -jsf.projectType=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30BF\u30A4\u30D7 -jsf.projectType.Description=\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u3084 web \u30B5\u30A4\u30C8\u306B\u3088\u308A\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u304A\u3088\u3073\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u304C\u884C\u306A\u308F\u308C\u308B\u969B\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u51E6\u7406\u65B9\u6CD5\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002 -jsf.projectType.DefaultBehaviour=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30BF\u30A4\u30D7\u3092\u6307\u5B9A\u3057\u3066\u3044\u306A\u3044\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067\u306F\u3001 \u5404\u30D0\u30FC\u30B8\u30E7\u30F3\u306B\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u30BF\u30A4\u30D7\u304C\u9069\u7528\u3055\u308C\u308B\u3088\u3046\u306B\u306A\u308A\u307E\u3059\u3002 -jsf.projectType.NotSpecifiedBehaviour=\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30BF\u30A4\u30D7\u3092\u6307\u5B9A\u3057\u306A\u3044\u5834\u5408\u3001 \u305D\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30BF\u30A4\u30D7\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u4F7F\u7528\u3055\u308C\u307E\u3059\u3002 -jsf.projectType.MoreInfo=\u8A73\u7D30\u306B\u3064\u3044\u3066\u306F https\://github.com/zanata/zanata/wiki/Project-Types \u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.projectType.NoSelection=-- \u9078\u629E\u306A\u3057 -- -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Remove=\u524A\u9664 -# translation auto-copied from project Fedora Installation Guide, version f18, document Trouble_During_x86_ppc-section-2-variablelist-1 -jsf.Save=\u4FDD\u5B58 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Search=\u691C\u7D22 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Status=\u30B9\u30C6\u30FC\u30BF\u30B9 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Update=\u66F4\u65B0 -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.Upload=\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9 -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.Username=\u30E6\u30FC\u30B6\u30FC\u540D -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author ykatabam -jsf.Version=\u30D0\u30FC\u30B8\u30E7\u30F3 -jsf.Projects=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 -# translation auto-copied from project Ovirt Engine Reports, version master, document adhoc_messages -jsf.Groups=\u30B0\u30EB\u30FC\u30D7 -jsf.Languages=\u8A00\u8A9E -jsf.More=\u8A73\u7D30 -jsf.ReportAProblem=\u554F\u984C\u306E\u5831\u544A -jsf.KnownIssues=\u65E2\u77E5\u306E\u554F\u984C -# translation auto-copied from project DocBook locales, version 1, document locale -jsf.Glossary=\u7528\u8A9E\u96C6 -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.Administration=\u7BA1\u7406 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Register=\u767B\u9332 -jsf.MyProfile=\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB -jsf.SearchProjects=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u691C\u7D22 -jsf.project.search.IncludeObsoleteTooltip=\u691C\u7D22\u306B\u65E7\u7248\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u542B\u307E\u305B\u308B -jsf.AboutZanata=Zanata \u306B\u3064\u3044\u3066 -# translation auto-copied from project Publican - Fedora brand, version 3, document Logos -jsf.Documentation=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8 -jsf.Wiki=Wiki -jsf.Blog=\u30D6\u30ED\u30B0 -# translation auto-copied from project CFSE, version sam-1.2, document app, author noriko -jsf.Support=\u30B5\u30DD\u30FC\u30C8 -jsf.IrcHelp=IRC \u30D8\u30EB\u30D7 -jsf.FAQ=FAQ -jsf.SiteMap=\u30B5\u30A4\u30C8\u30DE\u30C3\u30D7 -jsf.RunningVersionInfo=\#{messages['jsf.Zanata']} version \#{applicationConfiguration.version} (\#{applicationConfiguration.buildTimestamp}). -jsf.CopyrightNotice=&\#169; 2008-12 Red Hat, Inc and others. -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.Home=\u30DB\u30FC\u30E0 -jsf.server.EditHomePage.label=\u30DA\u30FC\u30B8\u30B3\u30F3\u30C6\u30F3\u30C4\u306E\u7DE8\u96C6 -jsf.server.EditHomePageCode.label=\u30DA\u30FC\u30B8\u30B3\u30FC\u30C9\u306E\u7DE8\u96C6 -jsf.server.EditHomePageCode.tooltip=\u6301\u7D9A\u72B6\u614B\u3067\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8\u306E\u30B3\u30FC\u30C9\u3092\u7DE8\u96C6\u3057\u307E\u3059\u3002 \u7DE8\u96C6\u30DA\u30FC\u30B8\u3067\u306F\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8\u306E\u7DE8\u96C6\u304C\u884C\u306A\u3048\u306A\u3044\u5834\u5408\u306B\u4FBF\u5229\u3067\u3059\u3002 -jsf.EditHomePage=\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8\u306E\u7DE8\u96C6 -jsf.CreateProject=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u4F5C\u6210 -jsf.FilterActiveProjects=\u30A2\u30AF\u30C6\u30A3\u30D6\u306A\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u304B\u3051\u308B -jsf.FilterReadOnlyProjects=\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u304B\u3051\u308B -jsf.FilterObsoleteProjects=\u65E7\u7248\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u304B\u3051\u308B -jsf.ProjectName=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D -jsf.NoProjectExists=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -jsf.SearchResultsForProjectSearch='\#{projectSearch.searchQuery}' \u306E\u7D50\u679C\u3092\u691C\u7D22 -jsf.projectSearch.searchQuery.title='\#{projectSearch.searchQuery}' \u306E\u554F\u3044\u5408\u308F\u305B\u306B\u4E00\u81F4\u3059\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C \#{projectSearch.resultSize} \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u898B\u3064\u304B\u308A\u307E\u3057\u305F -jsf.OnlyShowingFirstPagesizeResults=\u6700\u521D\u306E \#{projectSearch.pageSize} \u7D50\u679C\u306E\u307F\u3092\u8868\u793A\u3057\u307E\u3059\u3002 -jsf.CreateANewProject=\u65B0\u898F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u4F5C\u6210 -jsf.EditProject=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u7DE8\u96C6 -jsf.ProjectId=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 ID -jsf.ProjectIdExample=\u4F8B\: my-project -jsf.viewSourceFiles=\u30BD\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB\u306E\u8868\u793A -jsf.viewSourceFiles.Example=\u53EF\u8AAD\u5F62\u5F0F\u306E\u30BD\u30FC\u30B9\u3078\u306E\u30EA\u30F3\u30AF\u3001 https\://github.com/zanata/zanata \u306A\u3069 -jsf.SourceCheckoutUrl=\u30BD\u30FC\u30B9\u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\uFF0F\u30C1\u30A7\u30C3\u30AF\u30A2\u30A6\u30C8 -jsf.SourceCheckoutUrl.Example=\u30D0\u30FC\u30B8\u30E7\u30F3\u7BA1\u7406\u30BD\u30D5\u30C8\u30A6\u30A7\u30A2\u306B\u3088\u308B\u30BD\u30FC\u30B9\u306E\u30C1\u30A7\u30C3\u30AF\u30A2\u30A6\u30C8\u7528 URL\u3001 git@github.com\:zanata/zanata.git \u306A\u3069 -jsf.customizedLocaleMessage=\u30AB\u30B9\u30BF\u30DE\u30A4\u30BA\u3057\u305F\u30ED\u30B1\u30FC\u30EB\u4E00\u89A7\u3092\u8FFD\u52A0\u3057\u307E\u3059\u304B? -jsf.DisabledLocales=\u30ED\u30FC\u30B1\u30EB\u3092\u7121\u52B9\u306B\u3057\u307E\u3057\u305F -jsf.EnabledLocales=\u30ED\u30B1\u30FC\u30EB\u3092\u6709\u52B9\u306B\u3057\u307E\u3057\u305F -jsf.AddLocale=\u8FFD\u52A0 > -jsf.RemoveLocale=< \u524A\u9664 -jsf.RestrictRoleAccessMessage=\u7279\u5B9A\u306E\u30E6\u30FC\u30B6\u30FC\u30ED\u30FC\u30EB\u306B\u5BFE\u3057\u3066\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3078\u306E\u30A2\u30AF\u30BB\u30B9\u3092\u5236\u9650\u3057\u307E\u3059\u304B? -jsf.RestrictRoleAccessTooltip=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3078\u306E\u30A2\u30AF\u30BB\u30B9\u3092\u5236\u9650 -jsf.customizedValidationMessage=\u30AB\u30B9\u30BF\u30DE\u30A4\u30BA\u3057\u305F\u691C\u8A3C\u4E00\u89A7\u3092\u4F7F\u7528\u3057\u307E\u3059\u304B? -jsf.ProjectVersionId=\u30D0\u30FC\u30B8\u30E7\u30F3 ID -jsf.ReadOnlyVersions=\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u30D0\u30FC\u30B8\u30E7\u30F3 -jsf.ObsoleteVersions=\u65E7\u7248\u306E\u30D0\u30FC\u30B8\u30E7\u30F3 -jsf.DocumentCount=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\: -jsf.TranslateLinks=\u7FFB\u8A33\u30EA\u30F3\u30AF -jsf.Translate=\u7FFB\u8A33 -jsf.TranslateGWTDevMode=\u7FFB\u8A33 (GWT DevMode) -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.Open=\u958B\u304F -jsf.OpenGWTDevMode=\u958B\u304F (GWT DevMode) -jsf.ManageVersion=\u7BA1\u7406\u30D0\u30FC\u30B8\u30E7\u30F3 -jsf.EditVersion=\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u7DE8\u96C6 -jsf.SourceDocs=\u30BD\u30FC\u30B9\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8 -jsf.SourceDocuments=\u30BD\u30FC\u30B9\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8 -jsf.project.EditHomePage.label=\u30DA\u30FC\u30B8\u30B3\u30FC\u30C9\u306E\u7DE8\u96C6 -jsf.project.EditHomePage.tooltip=\u6301\u7D9A\u72B6\u614B\u3067\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8\u306E\u30B3\u30FC\u30C9\u3092\u7DE8\u96C6\u3057\u307E\u3059\u3002 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u7DE8\u96C6\u30DA\u30FC\u30B8\u3067\u306F\u30DB\u30FC\u30E0\u30DA\u30FC\u30B8\u306E\u7DE8\u96C6\u304C\u884C\u306A\u3048\u306A\u3044\u5834\u5408\u306B\u4FBF\u5229\u3067\u3059\u3002 -jsf.CreateVersion=\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u4F5C\u6210 -jsf.ManageMaintainers=\u30E1\u30F3\u30C6\u30CA\u30FC\u306E\u7BA1\u7406 -jsf.CopyTrans=\u7FFB\u8A33\u306E\u30B3\u30D4\u30FC -jsf.project.CopyTransOpts.tooltip=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30C7\u30D5\u30A9\u30EB\u30C8 \#{messages['jsf.CopyTrans']} \u30BB\u30C3\u30C6\u30A3\u30F3\u30B0\u3092\u8A2D\u5B9A\u3057\u307E\u3059\u3002 -jsf.ProjectMaintainers=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30E1\u30F3\u30C6\u30CA\u30FC -jsf.NoMaintainers=(\u30E1\u30F3\u30C6\u30CA\u30FC\u304C\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u305B\u3093) -jsf.project.RoleRestrictions=\u30ED\u30FC\u30EB\u306E\u5236\u9650 -jsf.project.ProjectRestrictedToFollowingRoles=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306F\u6B21\u306E\u30E6\u30FC\u30B6\u30FC\u30ED\u30FC\u30EB\u306B\u5BFE\u3057\u3066\u30A2\u30AF\u30BB\u30B9\u3092\u5236\u9650\u3057\u3066\u3044\u307E\u3059\u3002 -jsf.AddProjectMaintainer=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30E1\u30F3\u30C6\u30CA\u30FC\u306E\u8FFD\u52A0 -jsf.AreYouSureYouWishToRemoveThisPersonAsProjectMaintainer=\u672C\u5F53\u306B\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u3092\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30E1\u30F3\u30C6\u30CA\u30FC\u304B\u3089\u524A\u9664\u3057\u3066\u3044\u3088\u3044\u3067\u3059\u304B? -jsf.AddGroupMaintainer=\u30B0\u30EB\u30FC\u30D7\u30E1\u30F3\u30C6\u30CA\u30FC\u306E\u8FFD\u52A0 -jsf.AreYouSureYouWishToRemoveThisPersonAsGroupMaintainer=\u672C\u5F53\u306B\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u3092\u30B0\u30EB\u30FC\u30D7\u30E1\u30F3\u30C6\u30CA\u30FC\u304B\u3089\u524A\u9664\u3057\u3066\u3088\u3044\u3067\u3059\u304B? -jsf.YouAreNoLongerMaintainerForThisProject=\u30E6\u30FC\u30B6\u30FC\u306F\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30E1\u30F3\u30C6\u30CA\u30FC\u3067\u306F\u306A\u304F\u306A\u308A\u307E\u3057\u305F\u3002 -jsf.project.CopyTransOpts.title=\#{messages['jsf.CopyTrans']} \u30AA\u30D7\u30B7\u30E7\u30F3 -jsf.project.CopyTransOpts.saved=\#{messages['jsf.CopyTrans']} \u30AA\u30D7\u30B7\u30E7\u30F3\u304C\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F\u3002 -jsf.iteration.CopyTrans.pageTitle=\#{viewAllStatusAction.projectSlug}\:\#{viewAllStatusAction.iterationSlug} \u306E\u7FFB\u8A33\u3092\u30B3\u30D4\u30FC\u3059\u308B -# translation auto-copied from project Ovirt Engine Reports, version master, document adhoc_messages -jsf.iteration.CopyTrans.Condition=\u6761\u4EF6\: -jsf.iteration.CopyTrans.Condition.onContentMismatch=\u30B3\u30F3\u30C6\u30F3\u30C4\u306E\u4E0D\u4E00\u81F4\: -jsf.iteration.CopyTrans.Condition.onProjectMismatch=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u4E0D\u4E00\u81F4\: -jsf.iteration.CopyTrans.Condition.onContextMismatch=\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u306E\u4E0D\u4E00\u81F4 (resId\u3001 msgctxt)\: -jsf.iteration.CopyTrans.Condition.onDocIdMismatch=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8 Id \u306E\u4E0D\u4E00\u81F4 (\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u540D\u3068\u30D1\u30B9)\: -jsf.iteration.CopyTrans.Condition.final=\u3053\u308C\u4EE5\u5916\: -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.uicompat.Constants, author ykatabam -jsf.iteration.CopyTrans.Action=\u52D5\u4F5C -jsf.iteration.CopyTrans.Help.downgradeToFuzzy=\u7FFB\u8A33\u306F\u518D\u5229\u7528\u3057\u307E\u3059\u304C\u30D5\u30A1\u30B8\u30FC\u306E\u30DE\u30FC\u30AF\u3092\u4ED8\u3051\u307E\u3059\u3002 \u5F8C\u7D9A\u306E\u6761\u4EF6\u306B\u3064\u3044\u3066\u3082\u78BA\u8A8D\u3057\u307E\u3059\u3002 -jsf.iteration.CopyTrans.Help.ignore=\u7FFB\u8A33\u3092\u518D\u5229\u7528\u3059\u308B\u304B\u3057\u306A\u3044\u304B\u3092\u5224\u65AD\u3059\u308B\u969B\u3001 \u3053\u306E\u6761\u4EF6\u306F\u8003\u616E\u306B\u306F\u5165\u308C\u307E\u305B\u3093 (\u3053\u306E\u6761\u4EF6\u306F\u78BA\u8A8D\u305B\u305A\u30B9\u30AD\u30C3\u30D7\u3059\u308B)\u3002 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Start=\u958B\u59CB -jsf.iteration.CopyTrans.AlreadyStarted=\#{copyTransAction.projectIteration.project.name} \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E \#{copyTransAction.projectIteration.slug} \u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u300C\#{messages['jsf.CopyTrans']}\u300D\u306F\u3059\u3067\u306B \#{copyTransManager.getCopyTransProcessHandle( copyTransAction.projectIteration ).triggeredBy} \u306B\u3088\u3063\u3066\u958B\u59CB\u3055\u308C\u3066\u3044\u307E\u3059\u3002 -jsf.CopyTrans.ClickHereToViewProgress=\u9032\u6357\u3092\u78BA\u8A8D\u3059\u308B\u5834\u5408\u306F\u3053\u3053\u3092\u30EA\u30C3\u30AF\u3057\u307E\u3059\u3002 -jsf.iteration.CopyTrans.AlreadyStarted.flash=\u3053\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u306E \#{messages['jsf.CopyTrans']} \u306F\u4ED6\u306E\u30E6\u30FC\u30B6\u30FC\u306B\u3088\u3063\u3066\u65E2\u306B\u958B\u59CB\u3055\u308C\u3066\u3044\u307E\u3059\u3002 -jsf.iteration.CopyTrans.NoDocuments=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D0\u30FC\u30B8\u30F3\u306B\u306F\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306F\u3042\u308A\u307E\u305B\u3093\u3002 -jsf.iteration.CopyTrans.Started=\#{messages['jsf.CopyTrans']} \u304C\u958B\u59CB\u3055\u308C\u307E\u3057\u305F\u3002 -jsf.iteration.ShowAllLocales.title=\u30E6\u30FC\u30B6\u30FC\u306E\u30C1\u30FC\u30E0\u306F\u4EE5\u4E0B\u3067 \u5F37\u8ABF\u8868\u793A \u3055\u308C\u307E\u3059\u3002 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Refresh=\u66F4\u65B0 -jsf.RefreshTable=\u8868\u306E\u66F4\u65B0 -jsf.iteration.stats.OpenInWebEditor=\u7FFB\u8A33\u30A8\u30C7\u30A3\u30BF\u3067\u958B\u304F -jsf.Documents=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author ykatabam -jsf.Statistics=\u7D71\u8A08 -jsf.ByWords=\u5358\u8A9E\u6570 -jsf.Message=\u30E1\u30C3\u30BB\u30FC\u30B8\u6570 -jsf.stats.Total=\u5408\u8A08\: -jsf.stats.Translated=\u7FFB\u8A33\u6E08\u307F\: -jsf.stats.ShortHoursSuffix=\u6642\u9593 -jsf.NoContent=(\u30B3\u30F3\u30C6\u30F3\u30C4\u306A\u3057) -jsf.LastTranslated=\u6700\u5F8C\u306E\u7FFB\u8A33 -jsf.ConfigFile=\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB -jsf.GenerateProjectConfig=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306E\u751F\u6210 (zanata.xml) -jsf.iteration.CopyTrans=\u7FFB\u8A33\u306E\u30B3\u30D4\u30FC -jsf.iteration.CopyTrans.title=\u5225\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u304B\u3089\u627F\u8A8D\u6E08\u307F\u306E\u7FFB\u8A33\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3059\u3002 -jsf.JoinedGroups=\u53C2\u52A0\u3057\u3066\u3044\u308B\u30B0\u30EB\u30FC\u30D7 -jsf.iteration.CopyTrans.inProgress=\u7FFB\u8A33\u3092\u30B3\u30D4\u30FC\u4E2D... -jsf.iteration.CopyTrans.started=\#{viewAllStatusAction.copyTransStartTime} \u524D\u306B \#{pHandle.triggeredBy} \u306B\u3088\u3063\u3066\u958B\u59CB\u3055\u308C\u307E\u3057\u305F -jsf.iteration.CopyTrans.estimatedTimeRemaining=\u63A8\u5B9A\u3055\u308C\u308B\u6B8B\u308A\u6642\u9593\: \#{viewAllStatusAction.copyTransEstimatedTimeLeft} -jsf.group.FindGroup=\u30B0\u30EB\u30FC\u30D7\u306E\u691C\u7D22 -jsf.NoResultToDisplay=\u8868\u793A\u3059\u308B\u7D50\u679C\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.GroupName=\u30B0\u30EB\u30FC\u30D7\u540D -jsf.SelectGroup=\u30B0\u30EB\u30FC\u30D7\u306E\u9078\u629E -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.Select=\u9078\u629E -jsf.pager.NextPage=\u6B21\u3078 -jsf.pager.PreviousPage=\u623B\u308B -jsf.iteration.files.NoFiles=\u30D5\u30A1\u30A4\u30EB\u304C\u3042\u308A\u307E\u305B\u3093 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.iteration.files.Path=\u30D1\u30B9 -jsf.iteration.files.Filter.title=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u540D\u3067\u30D5\u30A3\u30EB\u30BF\u30FC -jsf.Upload.Title=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u3066\u73FE\u5728\u306E\u7FFB\u8A33\u3092\u30DE\u30FC\u30B8\u3059\u308B\uFF0F\u4E0A\u66F8\u304D\u3059\u308B -jsf.iteration.files.UploadFile=\u30D5\u30A1\u30A4\u30EB\u306E\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9 -jsf.iteration.files.Merge=\u30DE\u30FC\u30B8 -jsf.iteration.files.Merge.title=\u30C1\u30A7\u30C3\u30AF\u3059\u308B\u3068\u73FE\u5728\u306E\u30C7\u30FC\u30BF\u304C\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u305F\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306B\u30DE\u30FC\u30B8\u3055\u308C\u307E\u3059\u3002 \u30C1\u30A7\u30C3\u30AF\u3057\u306A\u3044\u3068\u73FE\u5728\u306E\u30C7\u30FC\u30BF\u306F\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u305F\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u3067\u3059\u3079\u3066\u4E0A\u66F8\u304D\u3055\u308C\u307E\u3059\u3002 -jsf.iteration.files.MergeCheckbox.Title=\u30C1\u30A7\u30C3\u30AF\u3059\u308B\u3068\u66F4\u65B0\u3055\u308C\u305F\u7FFB\u8A33\u304C\u66F8\u304D\u8FBC\u307E\u308C\u3001 \u305D\u308C\u4EE5\u5916\u306F\u5909\u66F4\u3055\u308C\u307E\u305B\u3093\u3002 -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.iteration.files.Download=\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 -jsf.iteration.files.dotpot=.pot -jsf.iteration.files.dotofflinepot=\u30AA\u30D5\u30E9\u30A4\u30F3 .pot -jsf.iteration.files.dotofflinepot.description=Zanata id \u3092\u683C\u7D0D\u3067\u304D\u308B msgctxt \u3092\u4F7F\u7528\u3057\u305F\u7279\u6B8A\u306A pot \u5F62\u5F0F\u3067\u3059\u3002 -jsf.iteration.files.dotofflinepot.purpose=\u30AA\u30D5\u30E9\u30A4\u30F3\u7FFB\u8A33\u3067\u306E\u5229\u7528\u306E\u307F\u3092\u76EE\u7684\u3068\u3057\u3066\u63D0\u4F9B\u3055\u308C\u3066\u3044\u308B\u305F\u3081\u3001 \u30BD\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB\u306E\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u306F\u3053\u306E\u5F62\u5F0F\u3067\u306F\u884C\u306A\u308F\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002 -jsf.iteration.files.dotpo=.po -jsf.iteration.files.dotofflinepo=\u30AA\u30D5\u30E9\u30A4\u30F3 .po -jsf.iteration.files.dotofflinepo.description=Zanata id \u3092\u683C\u7D0D\u3067\u304D\u308B msgctxt \u3092\u4F7F\u7528\u3057\u305F\u7279\u6B8A\u306A po \u5F62\u5F0F\u3067\u3059\u3002 -jsf.iteration.files.dotofflinepo.purpose=\u30AA\u30EA\u30B8\u30CA\u30EB\u3067\u306F po \u4EE5\u5916\u306E\u5F62\u5F0F\u3060\u3063\u305F\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E po \u7FFB\u8A33\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3059\u308B\u969B\u306B Zanata \u3067\u5FC5\u8981\u306B\u306A\u308B\u5F62\u5F0F\u3067\u3059\u3002 -jsf.iteration.files.ConfirmDocDeletion=\u672C\u5F53\u306B\u3053\u306E\u30BD\u30FC\u30B9\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? -jsf.iteration.files.DocumentDeleted=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u304C\u6B63\u3057\u304F\u524A\u9664\u3055\u308C\u307E\u3057\u305F\u3002 -jsf.iteration.files.ProcessDlgTitle=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D5\u30A1\u30A4\u30EB\u306E\u51E6\u7406\u4E2D... -jsf.iteration.files.UploadDocument=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9 -jsf.SupportedUploadFormats=\u5BFE\u5FDC\u30BF\u30A4\u30D7\: .pot .dtd .txt .odt .fodt .odp .fodp .ods .fods .odg .fodg .odb .odf -jsf.SourceLanguage=\u30BD\u30FC\u30B9\u8A00\u8A9E -jsf.iteration.files.DocumentPath=\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u30D1\u30B9 -jsf.ConfigFileForOfflineTranslation=\u30AA\u30D5\u30E9\u30A4\u30F3\u7FFB\u8A33\u306E\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB -jsf.GenerateProjectConfigSingleLocale=\u3053\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB (zanata.xml) \u3092\u30ED\u30B1\u30FC\u30EB \#{projectIterationFilesAction.localeId} \u3067\u751F\u6210\u3059\u308B -jsf.GenerateProjectConfigForOfflineTranslation=\u3053\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB (zanata.xml) \u3092\u30ED\u30B1\u30FC\u30EB \#{projectIterationFilesAction.localeId} \u3067\u751F\u6210\u3057\u3001 po \u30D5\u30A1\u30A4\u30EB\u306E\u30AA\u30D5\u30E9\u30A4\u30F3\u7FFB\u8A33\u3067\u4F7F\u7528\u3059\u308B\u7279\u6B8A\u306A\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30BF\u30A4\u30D7 'offlinepo' \u3092\u4F7F\u7528\u3057\u307E\u3059\u3002 -jsf.ConfigFileDisabledProjectNotSet=\u30E1\u30F3\u30C6\u30CA\u30FC\u306B\u3088\u308A\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30BF\u30A4\u30D7\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u306A\u3044\u305F\u3081\u7121\u52B9\u306B\u306A\u308A\u307E\u3059\u3002 -jsf.iteration.files.DownloadAllFiles=\u5168\u30D5\u30A1\u30A4\u30EB\u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 (zip) -jsf.iteration.files.DownloadAllFiles.title=\u7FFB\u8A33\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u3059\u3079\u3066\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u307E\u3059\u3002 -jsf.iteration.files.DownloadAllFilesOfflinePo=\u5168\u30D5\u30A1\u30A4\u30EB\u306E\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9 (\u30AA\u30D5\u30E9\u30A4\u30F3 po zip) -jsf.iteration.files.DownloadAllFilesOfflinePo.title=\u30AA\u30D5\u30E9\u30A4\u30F3\u7FFB\u8A33\u7528\u306E po \u5F62\u5F0F\u3067\u7FFB\u8A33\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u3059\u3079\u3066\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u307E\u3059\u3002 -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30BF\u30A4\u30D7\u306F 'Gettext' \u304B 'Podir' \u306B\u8A2D\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30E1\u30F3\u30C6\u30CA\u30FC\u306B\u9023\u7D61\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotSet=\u3053\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30BF\u30A4\u30D7\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30E1\u30F3\u30C6\u30CA\u30FC\u306B\u9023\u7D61\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.iteration.files.ConfirmDownloadAllFiles=\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u306E\u6E96\u5099\u3092\u884C\u306A\u3046\u305F\u3081\u3001 \u5B8C\u4E86\u306B\u306F\u6570\u5206\u304B\u304B\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\u3002 \u3088\u308D\u3057\u3044\u3067\u3059\u304B? -jsf.generatezip.ProgressLabel=\#{projectIterationZipFileAction.zipFilePrepHandle.currentProgress} \uFF0F \#{projectIterationZipFileAction.zipFilePrepHandle.maxProgress} -jsf.iteration.files.WhyCantITranslate=\u306A\u305C\u7FFB\u8A33\u3067\u304D\u306A\u3044\u306E\u3067\u3059\u304B? -jsf.iteration.files.translateDenied.NotLoggedIn=\u30E6\u30FC\u30B6\u30FC\u306F\u30ED\u30B0\u30A4\u30F3\u3057\u3066\u3044\u307E\u305B\u3093\u3002 -jsf.iteration.files.translateDenied.VersionIsReadOnly=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D0\u30FC\u30B8\u30E7\u30F3\u306F\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u3067\u3059\u3002 -jsf.iteration.files.translateDenied.VersionIsObsolete=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D0\u30FC\u30B8\u30E7\u30F3\u306F\u65E7\u7248\u3067\u3059\u3002 -jsf.iteration.files.translateDenied.UserNotInProjectRole=\u3053\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u7FFB\u8A33\u3059\u308B\u306B\u306F\u6B21\u306E\u30E6\u30FC\u30B6\u30FC\u30ED\u30FC\u30EB\u306B\u306A\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\: {0} -jsf.NoGroupExists=\u30B0\u30EB\u30FC\u30D7\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -jsf.groups.ShowActiveGroups=\u30A2\u30AF\u30C6\u30A3\u30D6\u306A\u30B0\u30EB\u30FC\u30D7\u306E\u8868\u793A -jsf.groups.ShowObsoleteGroups=\u65E7\u7248\u30B0\u30EB\u30FC\u30D7\u306E\u8868\u793A -jsf.GroupId=\u30B0\u30EB\u30FC\u30D7 ID -jsf.GroupIdExample=\u4F8B\: my-group -jsf.AddProjectVersions=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u8FFD\u52A0 -jsf.groups.FindProjectVersion=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u691C\u7D22 -jsf.NoResultToDisplayProjectSearch=\u8868\u793A\u3059\u308B\u7D50\u679C\u306F\u3042\u308A\u307E\u305B\u3093\u3002 \u76EE\u7684\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u30D0\u30FC\u30B8\u30E7\u30F3\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u304B\u3069\u3046\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -# translation auto-copied from project Ovirt Engine Reports, version master, document adhoc_messages -jsf.ManageSearch.SelectAll=\u3059\u3079\u3066\u9078\u629E -# translation auto-copied from project Ovirt Engine Reports, version master, document querybuilder_messages -jsf.AddSelected=\u9078\u629E\u9805\u76EE\u3092\u8FFD\u52A0 -jsf.EditGroup=\u30B0\u30EB\u30FC\u30D7\u306E\u7DE8\u96C6 -jsf.GroupMaintainers=\u30B0\u30EB\u30FC\u30D7\u30E1\u30F3\u30C6\u30CA\u30FC -jsf.CreateSupportedLanguage=\u65B0\u898F\u306E\u8A00\u8A9E\u3092\u8FFD\u52A0 -jsf.NativeName=\u30CD\u30A4\u30C6\u30A3\u30D6\u540D -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author nnakakit -jsf.Members=\u30E1\u30F3\u30D0\u30FC -jsf.LanguageTeamTitle=\#{languageTeamAction.locale.retrieveDisplayName()} \u30C1\u30FC\u30E0 -jsf.SizeMembers=\#{languageTeamAction.locale.members.size} \u30E1\u30F3\u30D0\u30FC -jsf.Coordinator=\u30B3\u30FC\u30C7\u30A3\u30CD\u30FC\u30BF\u30FC -jsf.JoinLanguageTeam=\u8A00\u8A9E\u30C1\u30FC\u30E0\u306B\u53C2\u52A0\u3059\u308B -jsf.LeaveLanguageTeam=\u8A00\u8A9E\u30C1\u30FC\u30E0\u304B\u3089\u9000\u4F1A\u3059\u308B -jsf.RequestToJoinLanguageTeam=\u30C1\u30FC\u30E0\u53C2\u52A0\u306E\u30EA\u30AF\u30A8\u30B9\u30C8 -jsf.contactLanguageTeamCoordinator=\u30C1\u30FC\u30E0\u306E\u30B3\u30FC\u30C7\u30A3\u30CD\u30FC\u30BF\u30FC\u306B\u9023\u7D61 -jsf.AddTeamMember=\u30C1\u30FC\u30E0\u30E1\u30F3\u30D0\u30FC\u306E\u8FFD\u52A0 -jsf.FindUsersToAdd=\u8FFD\u52A0\u3059\u308B\u30E6\u30FC\u30B6\u30FC\u306E\u691C\u7D22 -jsf.AlreadyInTeam=\u3059\u3067\u306B\u30C1\u30FC\u30E0\u306B\u5C5E\u3057\u3066\u3044\u307E\u3059 -jsf.EditHelpPageContent=\u30D8\u30EB\u30D7\u30DA\u30FC\u30B8\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u7DE8\u96C6 -jsf.ContactAdmin=\u7BA1\u7406\u8005\u306B\u9023\u7D61 -jsf.Entries=\u30A8\u30F3\u30C8\u30EA -jsf.Glossary.supportedFileFormat=\u5BFE\u5FDC\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\: PO \u3068 CSV -jsf.Glossary.SourceLocale.Title=\u30BD\u30FC\u30B9\u30ED\u30B1\u30FC\u30EB (PO \u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u306B\u306E\u307F\u9069\u7528) -jsf.TargetLanguage=\u30BF\u30FC\u30B2\u30C3\u30C8\u306E\u8A00\u8A9E -jsf.Glossary.TargetLocale.Title=\u30BF\u30FC\u30B2\u30C3\u30C8\u30ED\u30B1\u30FC\u30EB (PO \u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u306B\u306E\u307F\u9069\u7528) -jsf.Glossary.TreatSourceCommentsAsTarget=\u30BD\u30FC\u30B9\u306E\u30B3\u30E1\u30F3\u30C8\u3068\u53C2\u7167\u3092\u30BF\u30FC\u30B2\u30C3\u30C8\u306E\u30B3\u30E1\u30F3\u30C8\u3068\u3057\u3066\u51E6\u7406\u3057\u307E\u3059\u304B? -jsf.Glossary.TreatSourceCommentsAsTarget.Title=\u30C1\u30A7\u30C3\u30AF\u3059\u308B\u3068\u30BD\u30FC\u30B9\u306E\u30B3\u30E1\u30F3\u30C8\u3068\u53C2\u7167\u3092\u30BF\u30FC\u30B2\u30C3\u30C8\u306E\u30B3\u30E1\u30F3\u30C8\u3068\u3057\u3066\u4F7F\u7528\u3057\u307E\u3059\u3002 -jsf.Glossary.CommentColumnNames=\u30B3\u30E1\u30F3\u30C8\u30B3\u30E9\u30E0\u540D -jsf.Glossary.CommentColumnNames.Title=csv \u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u7528\u306B\u30AB\u30B9\u30BF\u30DE\u30A4\u30BA\u3057\u305F\u30B3\u30E1\u30F3\u30C8\u30B3\u30E9\u30E0\u306E\u30D8\u30C3\u30C0\u30FC\u3067\u3059\u3002 CSV \u306E\u5F62\u5F0F\: {source locale},{locale1},{locale2},...,{pos},{description} \u307E\u305F\u306F {source locale},{locale},{locale},...,{description1},{description2},... (CSV \u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u306B\u306E\u307F\u9069\u7528) -jsf.ThisActionCannotBeUndone=\u3053\u306E\u52D5\u4F5C\u306F\u5143\u306B\u623B\u305B\u307E\u305B\u3093 -jsf.SelectLocaleToDelete=\u524A\u9664\u3059\u308B\u30ED\u30B1\u30FC\u30EB\u306E\u9078\u629E -jsf.SignUp=\u30B5\u30A4\u30F3\u30A2\u30C3\u30D7 -jsf.NameToolTip=\u540D\u524D\u306E\u6700\u521D\u306E\u6587\u5B57\u306F\u5927\u6587\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.EmailToolTip=\u30E1\u30FC\u30EB\u306F username@domain.name \u306E\u5F62\u5F0F\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.UsernameToolTip=\u30E6\u30FC\u30B6\u30FC\u540D\u306F\u3059\u3079\u3066\u5C0F\u6587\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Password=\u30D1\u30B9\u30EF\u30FC\u30C9 -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.ConfirmPassword=\u30D1\u30B9\u30EF\u30FC\u30C9\u306E\u78BA\u8A8D -jsf.IAgreeToThe=\u540C\u610F\u3057\u307E\u3059 -# translation auto-copied from project CFSE, version 1.1, document app, author noriko -jsf.TermsOfUse=\u5229\u7528\u898F\u7D04 -jsf.register.LoginUsingOpenId=Open Id \u3092\u4F7F\u3063\u3066 \u3053\u3053 \u304B\u3089\u30ED\u30B0\u30A4\u30F3\u3059\u308B\u3053\u3068\u3082\u3067\u304D\u307E\u3059\u3002 -jsf.PleaseContactAdministrationToGetRegistrationLink=\u7BA1\u7406\u5074\u306B\u9023\u7D61\u3057\u767B\u9332\u30EA\u30F3\u30AF\u3092\u53D6\u5F97\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.ForgotYourPassword=\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u5FD8\u308C\u3066\u3057\u307E\u3063\u305F\u5834\u5408\u306F? -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.ResetPassword=\u30D1\u30B9\u30EF\u30FC\u30C9\u306E\u30EA\u30BB\u30C3\u30C8 -jsf.SubmitRequest=\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u9001\u4FE1 -jsf.ResetYourPassword=\u30D1\u30B9\u30EF\u30FC\u30C9\u306E\u30EA\u30BB\u30C3\u30C8 -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.NewPassword=\u65B0\u3057\u3044\u30D1\u30B9\u30EF\u30FC\u30C9 -jsf.OldPassword=\u53E4\u3044\u30D1\u30B9\u30EF\u30FC\u30C9 -# translation auto-copied from project CFSE, version sam-1.2, document app, author noriko -jsf.ChangePassword=\u30D1\u30B9\u30EF\u30FC\u30C9\u306E\u5909\u66F4 -# translation auto-copied from project CFSE, version 1.0.1, document app, author htaira -jsf.RememberMe=\u30E6\u30FC\u30B6\u30FC\u540D\u3092\u8A18\u61B6\u3059\u308B -jsf.login.openid.SelectProvider=\u3069\u306E\u3088\u3046\u306B\u3057\u3066\u30ED\u30B0\u30A4\u30F3\u3057\u3066\u3044\u307E\u3059\u304B? -jsf.login.openid.fedora=Fedora \u306E\u30E6\u30FC\u30B6\u30FC\u540D -jsf.login.openid.myopenid=MyOpenID \u30E6\u30FC\u30B6\u30FC -jsf.login.openid.yahoo=Yahoo \u306E\u30E6\u30FC\u30B6\u30FC\u540D -jsf.login.openid=Open ID -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.login.internal=\u30E6\u30FC\u30B6\u30FC\u540D -jsf.UsernameNotAvailable=\u30E6\u30FC\u30B6\u30FC\u540D "\#{userAction.username}" \u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093 -jsf.FedoraUsername=Fedora \u306E\u30E6\u30FC\u30B6\u30FC\u540D -jsf.ActivateAccount=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30C8 -jsf.ValidateEmail=\u30E1\u30FC\u30EB\u306E\u8A8D\u8A3C -jsf.InactiveAccount=\u975E\u30A2\u30AF\u30C6\u30A3\u30D6\u306A\u30A2\u30AB\u30A6\u30F3\u30C8 -jsf.inactiveaccount.PleaseSelectOne=\u30E6\u30FC\u30B6\u30FC\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u306F\u307E\u3060\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002 \u6B21\u306E\u3044\u305A\u308C\u304B\u306E\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.ResendActivationEmail=\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30B7\u30E7\u30F3\u30E1\u30FC\u30EB\u306E\u518D\u9001\u4FE1 -jsf.or=\u307E\u305F\u306F -jsf.inactiveaccount.UpdateAndResend=\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u66F4\u65B0\u3057\u3066\u304B\u3089\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30B7\u30E7\u30F3\u30E1\u30FC\u30EB\u3092\u518D\u9001\u4FE1\u3059\u308B\: -jsf.UpdateEmail=\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306E\u66F4\u65B0 -jsf.InvalidActivationKey=\u7121\u52B9\u306A\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30B7\u30E7\u30F3\u30AD\u30FC -jsf.ActivationLinkExpired=\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30B7\u30E7\u30F3\u30EA\u30F3\u30AF\u306E\u6709\u52B9\u671F\u9650\u5207\u308C\u3067\u3059\u3002 \u30B5\u30A4\u30F3\u30A4\u30F3\u3057\u3066\u304B\u3089 "\#{messages['jsf.ResendActivationEmail']}" \u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.uicompat.Constants, author miey -jsf.Error=\u30A8\u30E9\u30FC -jsf.ErrorTitle=\u73FE\u5728\u306E\u30A8\u30E9\u30FC\: -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.NoErrors=\u30A8\u30E9\u30FC\u306F\u3042\u308A\u307E\u305B\u3093 -jsf.EditProfile=\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u306E\u7DE8\u96C6 -jsf.ManageIdentities=ID \u306E\u7BA1\u7406 -jsf.identities.MergeAccount=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30DE\u30FC\u30B8 -jsf.identities.MergeAccount.tootip=2 \u3064\u306E Zanata \u30A2\u30AB\u30A6\u30F3\u30C8\u3092 1 \u3064\u306B\u30DE\u30FC\u30B8\u3057\u305F\u3044\u5834\u5408\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002 -jsf.ApiKey=API \u30AD\u30FC -jsf.YourCurrentApiKeyIs=\u30E6\u30FC\u30B6\u30FC\u306E\u73FE\u5728\u306E API \u30AD\u30FC\u3067\u3059 -jsf.NotGenerated=(\u751F\u6210\u3055\u308C\u3066\u3044\u307E\u305B\u3093) -jsf.apikey.ConfirmGenerate=\u672C\u5F53\u306B\u30E6\u30FC\u30B6\u30FC\u306E API \u30AD\u30FC\u3092\u751F\u6210\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? -jsf.ConfigurationForZanataini=\u8A2D\u5B9A [zanata.ini] -jsf.MaintainedProjects=\u7BA1\u7406\u3057\u3066\u3044\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 -jsf.LanguageTeams=\u8A00\u8A9E\u30C1\u30FC\u30E0 -jsf.MaintainedGroups=\u7BA1\u7406\u3057\u3066\u3044\u308B\u30B0\u30EB\u30FC\u30D7 -jsf.FirstExternalLoginMessage=\u4EE5\u4E0B\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u78BA\u8A8D\u3057\u3001 \u4FDD\u5B58\u3092\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u8A8D\u8A3C\u3057\u307E\u3059\u3002 -jsf.AccountDetails=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u8A73\u7D30 -jsf.identities.Title=ID -jsf.identities.ConfirmIdentityRemoval=\u672C\u5F53\u306B\u3053\u306E ID \u3092\u524A\u9664\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? \u3053\u306E ID \u3092\u4F7F\u7528\u3057\u3066\u30B5\u30A4\u30F3\u30A4\u30F3\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u306A\u304F\u306A\u308A\u307E\u3059\u3002 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.identities.Type=\u30BF\u30A4\u30D7 -jsf.identities.User=ID -jsf.identities.AddIdentity=\u65B0\u3057\u3044 ID \u306E\u8FFD\u52A0 -jsf.identities.Verify=ID \u306E\u78BA\u8A8D -jsf.profile.MergeAccount=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30DE\u30FC\u30B8 -jsf.profile.MergeAccount.info=\u30DE\u30FC\u30B8\u3057\u305F\u3044\u30A2\u30AB\u30A6\u30F3\u30C8\u306B\u30ED\u30B0\u30A4\u30F3\u3057\u307E\u3059\u3002 \u4EE5\u4E0B\u306B\u793A\u3059\u8A8D\u8A3C\u65B9\u6CD5\u306E\u3044\u305A\u308C\u304B\u3092\u4F7F\u7528\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 \u3053\u306E\u5F8C\u3001 \u78BA\u8A8D\u304C\u6C42\u3081\u3089\u308C\u307E\u3059\u3002 -jsf.profile.MergeAccount.confirm=\u5B9F\u884C\u3059\u308B -jsf.profile.MergeAccount.confirmationMessage=\u6B21\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u30DE\u30B8\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059\:

\u30E6\u30FC\u30B6\u30FC\u540D\: \#{accountMergeAction.obsoleteAccount.username}
\u540D\u524D\: \#{accountMergeAction.obsoleteAccount.person.name}
\u30E1\u30FC\u30EB\: \#{accountMergeAction.obsoleteAccount.person.email}

\u3053\u306E\u5909\u66F4\u306F\u6C38\u4E45\u7684\u306A\u5909\u66F4\u306B\u306A\u308B\u305F\u3081\u3001 \u5143\u306B\u623B\u3059\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002

\u4E0A\u8A18\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u306F\u975E\u30A2\u30AF\u30C6\u30A3\u30D6\u306B\u306A\u308A\u3001 \u3053\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30D1\u30FC\u30DF\u30C3\u30B7\u30E7\u30F3\u306F\u3059\u3079\u3066\u7121\u52B9\u306B\u306A\u308A\u307E\u3059\u3002 \u30E6\u30FC\u30B6\u30FC\u306E\u73FE\u5728\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u3053\u306E\u5168\u30D1\u30FC\u30DF\u30C3\u30B7\u30E7\u30F3\u3092\u7D99\u627F\u3059\u308B\u3053\u3068\u306B\u306A\u308A\u307E\u3059\u3002

\u672C\u5F53\u306B\u5B9F\u884C\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? -jsf.ServerConfiguration=\u30B5\u30FC\u30D0\u30FC\u8A2D\u5B9A -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.ManageUsers=\u30E6\u30FC\u30B6\u30FC\u306E\u7BA1\u7406 -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.ManageRoles=\u30ED\u30FC\u30EB\u306E\u7BA1\u7406 -jsf.ManageLanguage=\u8A00\u8A9E\u306E\u7BA1\u7406 -jsf.ManageSearch=\u691C\u7D22\u306E\u7BA1\u7406 -jsf.OverallStatistics=\u5168\u4F53\u7684\u306A\u7D71\u8A08 -jsf.RoleAssignmentRules=\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066\u306E\u30EB\u30FC\u30EB -jsf.ServerMonitoring=\u30B5\u30FC\u30D0\u30FC\u306E\u30E2\u30CB\u30BF\u30EA\u30F3\u30B0 -jsf.ProcessManager=\u30D7\u30ED\u30BB\u30B9\u30DE\u30CD\u30FC\u30B8\u30E3 -jsf.ServerUrl=\u30B5\u30FC\u30D0\u30FC URL -jsf.UrlToolTip=\u30B5\u30FC\u30D0\u30FC\u306E\u30D9\u30FC\u30B9 URL \u3067\u3059\u3002 \u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u306E\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u30D1\u30B9\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 (\u672B\u5C3E\u306B\u30B9\u30E9\u30C3\u30B7\u30E5\u306A\u3057)\u3002 -jsf.UrlExample=http\://example.com/zanata or http\://zanata.example.com \u306A\u3069 -jsf.RegisterUrl=\u767B\u9332 URL -jsf.RegisterUrlToolTip=\u30B5\u30FC\u30D0\u30FC\u7528\u306E\u30E6\u30FC\u30B6\u30FC\u767B\u9332 URL -jsf.RegisterUrlExample=/zanata/account/register or http\://example.com/register \u306A\u3069 -jsf.EmailDomainName=\u30E1\u30FC\u30EB\u306E\u30C9\u30E1\u30A4\u30F3\u540D -jsf.EmailDomainNameToolTip=\u30E1\u30FC\u30EB\u306E\u30C9\u30E1\u30A4\u30F3\u540D\u306F example.com \u306E\u5F62\u5F0F\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.EmailDomainNameExample=redhat.com \u306A\u3069 -jsf.config.AdminEmail=\u300C\u7BA1\u7406\u8005\u306B\u9023\u7D61\u300D\u7528\u306E\u30A2\u30C9\u30EC\u30B9 -jsf.config.AdminEmail.tooltip=\u300C\u7BA1\u7406\u8005\u306B\u9023\u7D61\u300D\u306E\u30D5\u30A9\u30FC\u30E0\u3092\u4F7F\u7528\u3057\u305F\u5834\u5408\u3001 \u3053\u308C\u3089\u306E\u30A2\u30C9\u30EC\u30B9\u306B\u30E1\u30FC\u30EB\u304C\u9001\u4FE1\u3055\u308C\u307E\u3059\u3002 -jsf.config.AdminEmail.DoesNotChangeUserEmail=\u3053\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u5165\u529B\u3057\u3066\u3082\u7BA1\u7406\u30E6\u30FC\u30B6\u30FC\u306E\u500B\u3005\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u304C\u5909\u66F4\u3055\u308C\u308B\u308F\u3051\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002 -jsf.email.EmailListToolTip=\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306F\u30B3\u30F3\u30DE\u4E00\u3064 (,) \u3067\u533A\u5207\u308A\u307E\u3059 -jsf.config.FromEmailAddr=\u9001\u4FE1\u5143\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9 -jsf.config.FromEmailAddr.tooltip=\u3053\u306E zanata \u30B5\u30FC\u30D0\u30FC\u3067\u9001\u4FE1\u3055\u308C\u308B\u30E1\u30FC\u30EB\u306E '\u9001\u4FE1\u5143' \u30D5\u30A3\u30FC\u30EB\u30C9\u306B\u4F7F\u7528\u3055\u308C\u307E\u3059\u3002 -jsf.config.EnableLogEmails=\u30ED\u30B0\u30E1\u30FC\u30EB\u3092\u6709\u52B9\u306B\u3059\u308B -jsf.config.EnableLogEmails.tooltip=\u30E1\u30FC\u30EB\u306B\u3088\u308B Zanata \u8A3A\u65AD\u30ED\u30B0\u60C5\u5831\u306E\u9001\u4FE1\u3092\u6709\u52B9\u307E\u305F\u306F\u7121\u52B9\u306B\u3057\u307E\u3059\u3002 -jsf.config.LogDestEmail=\u30ED\u30B0\u8A3A\u65AD\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9 -jsf.config.LogDestEmail.tooltip=\u30ED\u30B0\u8A18\u9332\u306E\u30A4\u30D9\u30F3\u30C8\u304C\u767A\u751F\u3059\u308B\u3068\u3053\u308C\u3089\u306E\u30A2\u30C9\u30EC\u30B9\u306B\u30E1\u30FC\u30EB\u304C\u9001\u4FE1\u3055\u308C\u307E\u3059\u3002 -jsf.config.LogEmailLevel=\u30E1\u30FC\u30EB\u306E\u30ED\u30B0\u30EC\u30D9\u30EB -jsf.config.LogEmailLevel.tooltip=\u30E1\u30FC\u30EB\u3067\u30ED\u30B0\u3092\u9001\u4FE1\u3059\u308B\u969B\u306E\u30ED\u30B0\u30EC\u30D9\u30EB\u3067\u3059\u3002 \u300C\u30A8\u30E9\u30FC\u300D\u306E\u5834\u5408\u306F\u30A8\u30E9\u30FC\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u307F\u3092\u9001\u4FE1\u3057\u3001 \u300C\u8B66\u544A\u300D\u306E\u5834\u5408\u306F\u8B66\u544A\u30E1\u30C3\u30BB\u30FC\u30B8\u3068\u30A8\u30E9\u30FC\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u4E21\u65B9\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002 -# translation auto-copied from project Fedora Installation Guide, version f18, document DiskEncryptionUserGuide -jsf.Warning=\u8B66\u544A -jsf.config.PiwikUrl=Piwik URL -jsf.config.Piwiktooltip=Piwik \u5206\u6790\u30C4\u30FC\u30EB\u306E URL \u3067\u3059\u3002 http\://localhost/piwik \u306A\u3069 -jsf.config.PiwikIdSite=Piwik Id -jsf.config.PiwikIdSitetooltip=Piwik \u306E Web \u30B5\u30A4\u30C8 Id -jsf.CreateNewUser=\u65B0\u898F\u30E6\u30FC\u30B6\u30FC\u306E\u4F5C\u6210 -jsf.MemberOf=\u6240\u5C5E\u5148 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author miey -jsf.Enabled=\u6709\u52B9 -jsf.AreYouSureYouWishToDeleteThisUserThisActionCannotBeUndone=\u672C\u5F53\u306B\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? \u3053\u306E\u52D5\u4F5C\u306F\u5143\u306B\u623B\u305B\u307E\u305B\u3093\u3002 -jsf.UserManager.delete.constraintViolation.error=\u3053\u306E\u30E6\u30FC\u30B6\u30FC\u306F\u30B7\u30B9\u30C6\u30E0\u304B\u3089\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u304C\u3001 \u975E\u30A2\u30AF\u30C6\u30A3\u30D6\u306B\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u3059\u3002 -jsf.AccountEnabled=\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u6709\u52B9\u306B\u3059\u308B -jsf.CreateRole=\u30ED\u30FC\u30EB\u306E\u4F5C\u6210 -jsf.AreYouSureYouWishToDeleteThisRoleThisActionCannotBeUndone=\u672C\u5F53\u306B\u3053\u306E\u30ED\u30FC\u30EB\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? \u3053\u306E\u52D5\u4F5C\u306F\u5143\u306B\u623B\u305B\u307E\u305B\u3093\u3002 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.Role=\u30ED\u30FC\u30EB -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.RoleDetails=\u30ED\u30FC\u30EB\u306E\u8A73\u7D30 -jsf.EnabledByDefault=\u30C7\u30D5\u30A9\u30EB\u30C8\u3067\u6709\u52B9 -jsf.AreYouSureYouWishToDeleteThisLanguageThisActionCannotBeUndone=\u672C\u5F53\u306B\u3053\u306E\u8A00\u8A9E\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? \u3053\u306E\u52D5\u4F5C\u306F\u5143\u306B\u623B\u305B\u307E\u305B\u3093\u3002 -jsf.AreYouSureYouWishToEnableThisLanguage=\u672C\u5F53\u306B\u3053\u306E\u8A00\u8A9E\u3092\u6709\u52B9\u306B\u3057\u3066\u3088\u3044\u3067\u3059\u304B? -jsf.AreYouSureYouWishToDisableThisLanguage=\u672C\u5F53\u306B\u3053\u306E\u8A00\u8A9E\u3092\u7121\u52B9\u306B\u3057\u3066\u3088\u3044\u3067\u3059\u304B? -jsf.language.manager.DisableByDefaultConfirmation=\u672C\u5F53\u306B\u3053\u306E\u8A00\u8A9E\u3092\u30C7\u30D5\u30A9\u30EB\u30C8\u3067\u7121\u52B9\u306B\u3057\u3066\u3088\u3044\u3067\u3059\u304B? -jsf.language.manager.EnableByDefaultConfirmation=\u672C\u5F53\u306B\u3053\u306E\u8A00\u8A9E\u3092\u30C7\u30D5\u30A9\u30EB\u30C8\u3067\u6709\u52B9\u306B\u3057\u3066\u3088\u3044\u3067\u3059\u304B? -jsf.TeamMembers=\u30C1\u30FC\u30E0\u30E1\u30F3\u30D0\u30FC -jsf.language.validation.ReplaceUnderscores=\u7F6E\u63DB -jsf.language.validation.Underscores=\u4E0B\u7DDA\u3067\u306F\u306A\u304F\u30C0\u30C3\u30B7\u30E5\u8A18\u53F7\u306B\u7F6E\u304D\u63DB\u3048\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.CountryCode=\u56FD\u30B3\u30FC\u30C9 -jsf.LanguageCode=\u8A00\u8A9E\u30B3\u30FC\u30C9 -jsf.Variant=\u30D0\u30EA\u30A2\u30F3\u30C8 -jsf.language.validation.Invalid=\u7121\u52B9\u306A\u8A00\u8A9E\u540D -jsf.language.validation.Existing=\u3053\u306E\u8A00\u8A9E\u306F\u65E2\u306B\u5B58\u5728\u3057\u3066\u3044\u307E\u3059 -jsf.language.validation.UnknownPluralForm=\u8B66\u544A\: \u8907\u6570\u306B\u95A2\u3059\u308B\u60C5\u5831\u304C\u3042\u308A\u307E\u305B\u3093\u3002 \u8907\u6570\u306A\u3057\u3068\u4EEE\u5B9A\u3057\u3066\u3044\u307E\u3059\u3002 -jsf.language.validation.SimilarLocaleFound=\u4F3C\u305F\u3088\u3046\u306A\u8A00\u8A9E\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\: -jsf.manageSearch.AllActions=(\u3059\u3079\u3066\u306E\u52D5\u4F5C) -# translation auto-copied from project Ovirt Engine Reports, version master, document querybuilder_messages -jsf.manageSearch.Table=\u8868 -jsf.manageSearch.AllTables=(\u3059\u3079\u3066\u306E\u8868) -jsf.manageSearch.purge=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u6D88\u53BB -jsf.manageSearch.purge.Description=\u65E2\u5B58\u3059\u308B\u8868\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u30A8\u30F3\u30C8\u30EA\u3059\u3079\u3066\u306B\u65E7\u7248\u306E\u30DE\u30FC\u30AF\u3092\u4ED8\u3051\u307E\u3059\u3002 -jsf.manageSearch.purge.ObsoletesOccupyDiskSpace=\u30C7\u30A3\u30B9\u30AF\u9818\u57DF\u3092\u5360\u6709\u3057\u3066\u3044\u308B\u30A8\u30F3\u30C8\u30EA\u3092\u65E7\u7248\u306B\u3057\u307E\u3059\u304C\u3001 \u691C\u7D22\u3092\u884C\u306A\u3063\u305F\u5834\u5408\u306B\u8FD4\u3055\u308C\u307E\u305B\u3093\u3002 -jsf.manageSearch.purge.RemoveByRunningOptimize=\u65E7\u7248\u306E\u30A8\u30F3\u30C8\u30EA\u306F\u6D88\u53BB\u5F8C\u306F\u3044\u3064\u3067\u3082\u6700\u9069\u5316\u3092\u5B9F\u884C\u3059\u308B\u3053\u3068\u3067\u5B8C\u5168\u524A\u9664\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002 -jsf.manageSearch.reindex=\u518D\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 -jsf.manageSearch.reindex.Description=\u7279\u5B9A\u306E\u8868\u5185\u306E\u884C\u3059\u3079\u3066\u306B\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4ED8\u3051\u3057\u307E\u3059\u3002 -jsf.manageSearch.reindex.OnlyWhenOutOfDate=\u30C7\u30FC\u30BF\u304C\u6301\u7D9A\u3055\u308C\u308B\u3068\u884C\u306B\u306F\u81EA\u52D5\u7684\u306B\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4ED8\u3051\u304C\u884C\u306A\u308F\u308C\u308B\u305F\u3081\u3001 \u3053\u306E\u52D5\u4F5C\u304C\u5FC5\u8981\u306A\u306E\u306F\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u671F\u9650\u304C\u5207\u308C\u305F\u5834\u5408\u306E\u307F\u3067\u3059 (\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u304B\u3089\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u5FA9\u5143\u3057\u305F\u5834\u5408\u3001 \u518D\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306B\u5931\u6557\u3057\u305F\u5F8C\u3001 \u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u30D5\u30A1\u30A4\u30EB\u304C\u524A\u9664\u3055\u308C\u305F\u5834\u5408\u306A\u3069)\u3002 -jsf.manageSearch.reindex.AllRowsWillBeReindexed=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5185\u306B\u30A8\u30F3\u30C8\u30EA\u304C\u65E2\u306B\u3042\u308B\u304B\u306A\u3044\u304B\u306B\u95A2\u3089\u305A\u3001 \u7279\u5B9A\u306E\u8868\u306E\u3059\u3079\u3066\u306E\u884C\u306B\u518D\u5EA6\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4ED8\u3051\u304C\u884C\u306A\u308F\u308C\u307E\u3059\u3002 -jsf.manageSearch.reindex.IndexedRowsWillBeUpdated=\u65E2\u306B\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4ED8\u3051\u304C\u884C\u306A\u308F\u308C\u305F\u884C\u306E\u30A8\u30F3\u30C8\u30EA\u304C\u66F4\u65B0\u3055\u308C\u307E\u3059\u3002 \u901A\u5E38\u3001 \u30A8\u30F3\u30C8\u30EA\u306B\u306F\u5F71\u97FF\u3042\u308A\u307E\u305B\u3093\u3002 -jsf.manageSearch.reindex.TimeAndMemoryWarning=\u8B66\u544A\: \u8868\u306E\u30B5\u30A4\u30BA\u304C\u5927\u304D\u3044\u3068\u3053\u306E\u52D5\u4F5C\u306B\u6570\u6642\u9593\u3092\u8981\u3059\u308B\u5834\u5408\u304C\u3042\u308B\u305F\u3081\u3001 \u30E1\u30E2\u30EA\u30FC\u4F7F\u7528\u91CF\u304C\u30D9\u30FC\u30B9\u30E9\u30A4\u30F3\u3092\u8D8A\u3048\u5927\u5E45\u306B\u5897\u52A0\u3059\u308B\u3053\u3068\u306B\u306A\u308A\u307E\u3059\u3002 -jsf.manageSearch.reindex.RunDuringOffPeak=\u3053\u306E\u64CD\u4F5C\u306F\u3001 \u30B5\u30FC\u30D0\u30FC\u306E\u5E73\u5747\u7684\u306A\u30E1\u30E2\u30EA\u30FC\u4F7F\u7528\u304C\u6700\u5C0F\u9650\u3068\u306A\u308B\u30AA\u30D5\u30D4\u30FC\u30AF\u306E\u6642\u9593\u5E2F\u306B\u884C\u306A\u3046\u3053\u3068\u3092\u5F37\u304F\u63A8\u5968\u3057\u307E\u3059\u3002 -jsf.manageSearch.optimize=\u6700\u9069\u5316 -jsf.manageSearch.optimize.Description=\u691C\u7D22\u901F\u5EA6\u3092\u6700\u5927\u9650\u306B\u9AD8\u3081\u308B\u305F\u3081\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u30A8\u30F3\u30C8\u30EA\u3092\u8ABF\u6574\u3057\u307E\u3059\u3002 -jsf.manageSearch.optimize.RemovesObsoleteEntries=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u304B\u3089\u65E7\u7248\u306E\u30A8\u30F3\u30C8\u30EA\u3082\u3059\u3079\u3066\u524A\u9664\u3057\u307E\u3059\u3002 -jsf.manageSearch.optimize.WillNotInfluenceIndexTime=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4ED8\u3051\u306E\u6642\u9593\u306B\u306F\u5F71\u97FF\u3057\u307E\u305B\u3093\u3002 -jsf.manageSearch.optimize.TempFileWarning=\u8B66\u544A\: \u3053\u306E\u64CD\u4F5C\u3067\u306F\u3001 \u73FE\u5728\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u30B5\u30A4\u30BA\u3068\u307B\u307C\u540C\u30B5\u30A4\u30BA\u306E\u30C7\u30A3\u30B9\u30AF\u7A7A\u304D\u9818\u57DF\u3092\u5FC5\u8981\u3068\u3059\u308B\u4E00\u6642\u30D5\u30A1\u30A4\u30EB\u304C\u4F7F\u7528\u3055\u308C\u307E\u3059\u3002 -jsf.ManageSearch.SelectNone=\u9078\u629E\u3092\u30AF\u30EA\u30A2 -jsf.ManageSearch.PerformSelectedActions=\u9078\u629E\u3057\u305F\u52D5\u4F5C\u3092\u5B9F\u884C\u3059\u308B -jsf.ManageSearch.CurrentProgress=\u73FE\u5728\u306E\u9032\u6357 -jsf.ManageSearch.NoOperationsRunning=\u5B9F\u884C\u4E2D\u306E\u64CD\u4F5C\u306F\u3042\u308A\u307E\u305B\u3093 -jsf.ManageSearch.Completed=\u6B63\u5E38\u306B\u5B8C\u4E86\u3057\u307E\u3057\u305F (\#{reindexAction.elapsedTime} \u306E\u5B9F\u884C\u6642\u9593) -jsf.ManageSearch.Aborted=\u30E6\u30FC\u30B6\u30FC\u306B\u3088\u308A\u505C\u6B62\u3055\u308C\u307E\u3057\u305F (\#{reindexAction.elapsedTime} \u306E\u5B9F\u884C\u6642\u9593) -jsf.manageSearch.ErrorMessage=\u30A8\u30E9\u30FC\u306E\u305F\u3081\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u4E00\u90E8\u306F\u518D\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4ED8\u3051\u304C\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 \u8A73\u7D30\u306B\u3064\u3044\u3066\u306F\u30B5\u30FC\u30D0\u30FC\u30ED\u30B0\u3092\u3054\u89A7\u304F\u3060\u3055\u3044\u3002 -jsf.manageSearch.PleaseReindex=\u691C\u7D22\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u304C\u6700\u65B0\u306E\u72B6\u614B\u3068\u306A\u308B\u3088\u3046\u518D\u5EA6\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u4ED8\u3051\u3092\u884C\u306A\u3063\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.manageSearch.ProgressMessage=\ \#{reindexAction.reindexCount} \u306E\u3046\u3061 \#{reindexAction.reindexProgress} \u306E\u52D5\u4F5C\u304C\u5B8C\u4E86 -jsf.manageSearch.CurrentTable=\u8868\u306E\u51E6\u7406\u4E2D\: \#{reindexAction.currentClass} -jsf.ManageSearch.ElapsedTime=\u5B9F\u884C\u6642\u9593\: \#{reindexAction.elapsedTime} -jsf.ManageSearch.RemainingTime=\u6B8B\u308A\u6642\u9593 (\u6982\u7B97)\: \#{reindexAction.estimatedTimeRemaining} -jsf.ManageSearch.Abort=\u505C\u6B62 -# translation auto-copied from project Publican, version 3, document publican -jsf.Untranslated=\u672A\u7FFB\u8A33 -jsf.rolerules.CreateRule=\u65B0\u3057\u3044\u30EB\u30FC\u30EB -jsf.rolerules.CreateRoleAssignmentRule=\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066\u306E\u30EB\u30FC\u30EB\u3092\u4F5C\u6210 -jsf.rolerules.EditRoleAssignmentRule=\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066\u306E\u30EB\u30FC\u30EB\u3092\u7DE8\u96C6 -jsf.rolerules.ConfirmDelete=\u672C\u5F53\u306B\u3053\u306E\u30EB\u30FC\u30EB\u3092\u524A\u9664\u3057\u3066\u3082\u3088\u3044\u3067\u3059\u304B? -jsf.rolerules.Description=\u30ED\u30FC\u30EB\u5272\u308A\u5F53\u3066\u306E\u30EB\u30FC\u30EB \u3092\u4F7F\u7528\u3059\u308B\u3068\u3001 \u7279\u5B9A\u306E\u30E6\u30FC\u30B6\u30FC\u304C\u30B5\u30A4\u30F3\u30A4\u30F3\u3057\u305F\u6642\u306B\u3001 \u305D\u306E\u30E6\u30FC\u30B6\u30FC\u306B\u81EA\u52D5\u7684\u306B\u30E6\u30FC\u30B6\u30FC\u30ED\u30FC\u30EB\u3092\u5272\u308A\u5F53\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002 \u30E6\u30FC\u30B6\u30FC\u306E ID (\u30E6\u30FC\u30B6\u30FC\u540D) \u304C\u30D1\u30BF\u30FC\u30F3\u306B\u4E00\u81F4\u3057\u3001 \u6307\u5B9A\u306E\u65B9\u6CD5\u3067\u8A8D\u8A3C\u3055\u308C\u308B\u3068 (Open Id \u306A\u3069 - \u5229\u7528\u53EF\u80FD\u306A\u5834\u5408 )\u3001 Zanata \u306B\u3088\u308A\u81EA\u52D5\u7684\u306B\u6307\u5B9A\u306E\u30E6\u30FC\u30B6\u30FC\u30ED\u30FC\u30EB\u304C\u305D\u306E\u30E6\u30FC\u30B6\u30FC\u306B\u5272\u308A\u5F53\u3066\u3089\u308C\u308B\u3088\u3046\u306B\u306A\u308A\u307E\u3059\u3002 -jsf.rolerules.PolicyName=\u30DD\u30EA\u30B7\u30FC\u540D -jsf.rolerules.PolicyName.tooltip=\u4EBA\u79F0\u306E\u305F\u3081\u30E6\u30FC\u30B6\u30FC\u306B\u3088\u308A\u4F7F\u7528\u3055\u308C\u308B\u8A8D\u8A3C\u30DD\u30EA\u30B7\u30FC\u3067\u3059\u3002\u672A\u9078\u629E\u306E\u307E\u307E\u306B\u3059\u308B\u3068\u3059\u3079\u3066\u306E\u30DD\u30EA\u30B7\u30FC\u304C\u9069\u7528\u3055\u308C\u307E\u3059\u3002 -jsf.rolerules.IdentityPattern=ID \u306E\u30D1\u30BF\u30FC\u30F3 -jsf.rolerules.IdentityPattern.tooltip=\u3053\u306E\u30EB\u30FC\u30EB\u3092\u30E6\u30FC\u30B6\u30FC ID \u306B\u9069\u7528\u3059\u308B\u304B\u3069\u3046\u304B\u3092\u6307\u5B9A\u3059\u308B\u6B63\u898F\u8868\u73FE\u3067\u3059\u3002 \u30E6\u30FC\u30B6\u30FC ID \u306F\u8A8D\u8A3C\u30E1\u30AB\u30CB\u30BA\u30E0\u306B\u3088\u3063\u3066\u7570\u306A\u308B\u70B9\u306B\u6CE8\u610F\u3057\u3066\u304F\u3060\u3055\u3044\u3002 \u3053\u306E\u5024\u3092\u7A7A\u767D\u306E\u307E\u307E\u306B\u3059\u308B\u3068\u3001 \u30EB\u30FC\u30EB\u304C\u3059\u3079\u3066\u306E\u30E6\u30FC\u30B6\u30FC ID\u306B\u9069\u7528\u3055\u308C\u308B\u3053\u3068\u306B\u306A\u308A\u307E\u3059\u3002 -jsf.rolerules.RoleToAssign=\u5272\u308A\u5F53\u3066\u308B\u30ED\u30FC\u30EB -jsf.rolerules.RoleToAssign.tooltip=\u30EB\u30FC\u30EB\u306E\u6761\u4EF6\u3092\u6E80\u305F\u3057\u305F\u5834\u5408\u306B\u306E\u307F\u3001 \u30E6\u30FC\u30B6\u30FC\u306E\u30ED\u30B0\u30A4\u30F3\u6642\u306B\u81EA\u52D5\u7684\u306B\u5272\u308A\u5F53\u3066\u3089\u308C\u308B\u30ED\u30FC\u30EB\u3067\u3059\u3002 -jsf.processmanager.TotalRunning=\u5B9F\u884C\u4E2D\u30D7\u30ED\u30BB\u30B9\u306E\u5408\u8A08 -jsf.processmanager.TotalFinished=\u7D42\u4E86\u6E08\u307F\u30D7\u30ED\u30BB\u30B9\u306E\u5408\u8A08 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.processmanager.Type=\u30BF\u30A4\u30D7 -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author nnakakit -jsf.processmanager.status.Stopped=\u505C\u6B62 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.uicompat.Constants, author ykatabam -jsf.processmanager.status.Running=\u5B9F\u884C\u4E2D -jsf.processmanager.status.WaitingToStop=\u505C\u6B62\u3092\u5F85\u6A5F\u4E2D -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author nnakakit -jsf.processmanager.Progress=\u9032\u6357 -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author noriko -jsf.processmanager.StartTime=\u8D77\u52D5\u6E08\u307F -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author noriko -jsf.processmanager.FinishTime=\u7D42\u4E86\u6E08\u307F -# translation auto-copied from project CFSE, version sam-1.2, document app, author nnakakit -jsf.processmanager.Duration=\u671F\u9593 -# translation auto-copied from project Ovirt Engine Reports, version master, document querybuilder_messages -jsf.email.From=\u5DEE\u51FA\u4EBA -jsf.email.ReplyAddress=\u8FD4\u4FE1\u5148 -jsf.email.ReplyAddress.description=(\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9) -# translation auto-copied from project Ovirt Engine Reports, version master, document jasperserver_messages -jsf.email.Subject=\u4EF6\u540D -jsf.AdditionalInfo=\u8A73\u7D30\u306A\u60C5\u5831 -# translation auto-copied from project oVirt, version rhevm-3.2, document frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/org.ovirt.engine.ui.webadmin.ApplicationConstants, author nnakakit -jsf.email.MessageBody=\u30E1\u30C3\u30BB\u30FC\u30B8 -jsf.email.Send=\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u9001\u4FE1 -jsf.NoProjects=\u8868\u793A\u3067\u304D\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -jsf.SelectProjectVersions=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u9078\u629E -jsf.NoProjectVersionSelected=\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30D0\u30FC\u30B8\u30E7\u30F3\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002 -jsf.ClickSendMessageToProceedRequest=\u8A73\u7D30\u60C5\u5831\u3092\u5165\u529B\u3057\u3066\u300C\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u9001\u4FE1\u300D\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u5148\u306B\u9032\u3080 -jsf.email.JoinGroupRequest.Subject=\u30B0\u30EB\u30FC\u30D7 '\#{versionGroupJoinAction.groupName}' \u3078\u306E\u53C2\u52A0\u30EA\u30AF\u30A8\u30B9\u30C8 -jsf.RequestAddProjectToGroup=\u30B0\u30EB\u30FC\u30D7\u3078\u306E\u53C2\u52A0\u30EA\u30AF\u30A8\u30B9\u30C8 -jsf.AlreadyInGroup=\u65E2\u306B\u30B0\u30EB\u30FC\u30D7\u306E\u30E1\u30F3\u30D0\u30FC\u3067\u3059 -jsf.email.joingrouprequest.AdditionalInfoMessage=\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u5186\u6ED1\u306B\u51E6\u7406\u3055\u308C\u308B\u3088\u3046\u3001 \u8A73\u7D30\u60C5\u5831\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002 \u3053\u306E\u60C5\u5831\u306F\u30E1\u30F3\u30C6\u30CA\u30FC\u304C\u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u51E6\u7406\u3092\u884C\u306A\u3046\u969B\u306B\u4F7F\u7528\u3055\u308C\u307E\u3059\u3002 -jsf.RequestToJoinLanguageTeamTitle='\#{sendEmail.locale.localeId.id}' \u8A00\u8A9E\u30C1\u30FC\u30E0\u3078\u306E\u53C2\u52A0\u30EA\u30AF\u30A8\u30B9\u30C8 -jsf.email.joinrequest.Subject=\u30E6\u30FC\u30B6\u30FC '\#{sendEmail.fromLoginName}' \u304C '\#{sendEmail.locale.localeId.id}' \u8A00\u8A9E\u30C1\u30FC\u30E0\u3078\u306E\u53C2\u52A0\u3092\u5E0C\u671B\u3057\u3066\u3044\u307E\u3059 -jsf.email.ContactCoordinatorTitle='\#{sendEmail.locale.retrieveDisplayName()}' \u30B3\u30FC\u30C7\u30A3\u30CD\u30FC\u30BF\u30FC\u306B\u9023\u7D61 -jsf.contactLanguageTeamCoordinatorForLocale='\#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()})' \u8A00\u8A9E\u30C1\u30FC\u30E0\u306E\u30B3\u30FC\u30C7\u30A3\u30CD\u30FC\u30BF\u30FC\u306B\u9023\u7D61 -jsf.email.YouAreReceivingThisMailBecause=\u672C\u30E1\u30FC\u30EB\u306F\u4EE5\u4E0B\u306E\u7406\u7531\u3067\u9001\u4FE1\u3055\u308C\u307E\u3057\u305F\u3002 -jsf.email.GeneratedFromZanataServerAt=\u3053\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u306F\u6B21\u3067\u5B9F\u884C\u3057\u3066\u3044\u308B Zanata \u306B\u3088\u308A\u751F\u6210\u3055\u308C\u307E\u3057\u305F\: -jsf.Account.ActivationMessage=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30C8\u7528\u30EA\u30F3\u30AF\u304C\u8A18\u8F09\u3055\u308C\u305F\u30E1\u30FC\u30EB\u304C\u30E6\u30FC\u30B6\u30FC\u306B\u9001\u4FE1\u3055\u308C\u307E\u3059\u3002 -jsf.email.activation.Subject=Zanata \u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30B7\u30E7\u30F3 -jsf.email.activation.register.DearName=\#{emailServiceImpl.toName} \u69D8 -jsf.email.activation.profile.DearName=\#{profileAction.name} \u69D8 -jsf.email.activation.ClickLinkToActivateAccount=\u6B21\u306E\u30EA\u30F3\u30AF\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30C8\u3057\u3066\u304F\u3060\u3055\u3044\: -jsf.email.activation.Link=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30B7\u30E7\u30F3\u30EA\u30F3\u30AF -jsf.email.alternate.copyPasteMessage=\u307E\u305F\u306F\u3001 \u6B21\u306E URL \u3092\u30B3\u30D4\u30FC\u3057\u3066\u3054\u4F7F\u7528\u306E\u30D6\u30E9\u30A6\u30B6\u306B\u8CBC\u308A\u4ED8\u3051\u308B\u3053\u3068\u3082\u3067\u304D\u307E\u3059\u3002 -jsf.UrlExpireMessage=URL \u306F 24 \u6642\u9593\u5F8C\u306B\u6709\u52B9\u671F\u9650\u5207\u308C\u3068\u306A\u308A\u307E\u3059\u3002 -jsf.email.accountchange.Subject=Zanata \u30E1\u30FC\u30EB\u5909\u66F4\u306E\u78BA\u8A8D -jsf.email.accountchange.DearName=\#{profileAction.name} \u69D8 -jsf.email.accountchange.Message=Zanata \u3067\u306F\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u3092 \#{profileAction.email} \u3078\u5909\u66F4\u3059\u308B\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u53D7\u3051\u53D6\u308A\u307E\u3057\u305F\u3002 -jsf.email.accountchange.Message2=\u30EA\u30AF\u30A8\u30B9\u30C8\u3057\u3066\u3044\u306A\u3044\u3001 \u306A\u305C\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u9001\u4FE1\u3055\u308C\u305F\u306E\u304B\u308F\u304B\u3089\u306A\u3044\u5834\u5408\u306F\u3001 \u81F3\u6025\u3001 Zanata \u30B7\u30B9\u30C6\u30E0\u7BA1\u7406\u8005\u306B\u3054\u9023\u7D61\u304F\u3060\u3055\u3044\u3002 -jsf.email.accountchange.ConfirmationLink=\u30E1\u30FC\u30EB\u306E\u5909\u66F4\u3092\u78BA\u8A8D\u3059\u308B\u5834\u5408\u306F\u3053\u3053\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u307E\u3059 -jsf.email.usernamechange.Subject=\u30E6\u30FC\u30B6\u30FC\u306E Zanata \u30E6\u30FC\u30B6\u30FC\u540D\u304C\u5909\u66F4\u3055\u308C\u307E\u3057\u305F\u3002 -jsf.email.usernamechange.DearName=\#{userAction.getName(userAction.username)} \u69D8 -jsf.email.usernamechange.Content=\u30E6\u30FC\u30B6\u30FC\u306E Zanata \u30E6\u30FC\u30B6\u30FC\u540D\u306F\u3001 \u6700\u8FD1\u30B7\u30B9\u30C6\u30E0\u7BA1\u7406\u8005\u3088\u308A\u5909\u66F4\u3055\u308C\u3066\u3044\u307E\u3059\u3002 \u30EA\u30AF\u30A8\u30B9\u30C8\u3057\u3066\u3044\u306A\u3044\u3001 \u306A\u305C\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u9001\u4FE1\u3055\u308C\u305F\u306E\u304B\u308F\u304B\u3089\u306A\u3044\u5834\u5408\u306F\u3001 \u81F3\u6025\u3001 Zanata \u30B7\u30B9\u30C6\u30E0\u7BA1\u7406\u8005\u306B\u3054\u9023\u7D61\u304F\u3060\u3055\u3044\u3002 -jsf.email.usernamechange.YourNewUsername=\u30E6\u30FC\u30B6\u30FC\u306E\u65B0\u3057\u3044\u30E6\u30FC\u30B6\u30FC\u540D\u306F \#{userAction.username}' \u3067\u3059 -jsf.email.usernamechange.ResetPassword=\u6B21\u306B\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u30EA\u30BB\u30C3\u30C8\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 \u4EE5\u4E0B\u306E\u30EA\u30F3\u30AF\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.email.usernamechange.ClickLinkForPasswordReset=\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u30EA\u30BB\u30C3\u30C8\u3059\u308B\u306B\u306F\u3053\u3053\u3092\u30AF\u30EA\u30C3\u30AF -jsf.email.passwordreset.Subject=Zanata \u30D1\u30B9\u30EF\u30FC\u30C9\u30EA\u30BB\u30C3\u30C8\u306E\u30EA\u30AF\u30A8\u30B9\u30C8 -jsf.email.passwordreset.DearName=\#{passwordResetRequest.account.person.name} \u69D8 -jsf.email.passwordreset.FollowLinkToResetPassword=\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u30EA\u30BB\u30C3\u30C8\u3059\u308B\u5834\u5408\u306F\u4EE5\u4E0B\u306E\u30EA\u30F3\u30AF\u306B\u5F93\u3063\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.email.passwordreset.IgnoreIfNotRequested=\u660E\u3089\u304B\u306B\u30D1\u30B9\u30EF\u30FC\u30C9\u30EA\u30BB\u30C3\u30C8\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u884C\u306A\u3063\u3066\u3044\u306A\u3044\u5834\u5408\u306F\u3001 \u3053\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u306F\u7121\u8996\u3057\u3066\u9802\u3044\u3066\u69CB\u3044\u307E\u305B\u3093\u3002 -jsf.email.admin.SentNotification=\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u7BA1\u7406\u8005\u306B\u9001\u4FE1\u3055\u308C\u307E\u3057\u305F -jsf.email.admin.SubjectPrefix='\#{sendEmail.fromLoginName}' \u304B\u3089\u306E Zanata \u30E6\u30FC\u30B6\u30FC\u30E1\u30FC\u30EB\: -jsf.ZanataAdministrator=Zanata \u7BA1\u7406\u8005 -jsf.email.admin.DearAdmin=\u7BA1\u7406\u8005\u306E\u65B9\u3078 -jsf.email.admin.UserMessageIntro=id \u304C '\#{sendEmail.fromLoginName}' \u306E Zanata \u30E6\u30FC\u30B6\u30FC '\#{sendEmail.fromName}' \u3055\u3093\u3088\u308A\u6B21\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u9001\u4FE1\u3055\u308C\u307E\u3057\u305F\: -jsf.email.ReplyInstructions=\#{sendEmail.fromName} \u3055\u3093\u5B9B\u306E\u8FD4\u4FE1\u30E1\u30FC\u30EB\u3092 \#{sendEmail.replyEmail} \u306B\u9001\u4FE1\u3067\u304D\u307E\u3059 -jsf.email.admin.ReceivedReason=\u30E6\u30FC\u30B6\u30FC\u306F\u30B7\u30B9\u30C6\u30E0\u8A2D\u5B9A\u5185\u306E\u7BA1\u7406\u8005\u306B\u306A\u308A\u307E\u3059 -jsf.email.admin.user.ReceivedReason=\u30E6\u30FC\u30B6\u30FC\u306F\u7BA1\u7406\u8005\u3067\u3059 -jsf.email.coordinator.SentNotification=\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u304C \#{sendEmail.locale.retrieveNativeName()} \u8A00\u8A9E\u30C1\u30FC\u30E0\u306B\u9001\u4FE1\u3055\u308C\u307E\u3057\u305F -jsf.email.coordinator.SubjectPrefix=Zanata\: \#{sendEmail.locale.localeId.id} \u8A00\u8A9E\u30C1\u30FC\u30E0\: '\#{sendEmail.fromLoginName}' \u304B\u3089\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\: -jsf.email.coordinator.DearCoordinator=\u8A00\u8A9E\u30C1\u30FC\u30E0\u306E\u30B3\u30FC\u30C7\u30A3\u30CD\u30FC\u30BF\u30FC\u306E\u65B9\u3078 -jsf.email.coordinator.UserMessageIntro=\ id \u304C '\#{sendEmail.fromLoginName}' \u306E Zanata \u30E6\u30FC\u30B6\u30FC '\#{sendEmail.fromName}' \u3055\u3093\u3088\u308A \#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()}) \u8A00\u8A9E\u30C1\u30FC\u30E0\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u9001\u4FE1\u3055\u308C\u307E\u3057\u305F\: -jsf.email.coordinator.ResponseInstructions=\u4EE5\u4E0B\u306E\u30EA\u30F3\u30AF\u3092\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3068\u3001 \#{sendEmail.locale.localeId.id} \u8A00\u8A9E\u30C1\u30FC\u30E0\u306E\u30DA\u30FC\u30B8\u306B\u76F4\u63A5\u79FB\u52D5\u3067\u304D\u307E\u3059\u3002 \u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u51E6\u7406\u3092\u5B8C\u4E86\u3057\u305F\u3089 \#{sendEmail.fromName} \u3055\u3093\u5B9B\u3066\u306E\u8FD4\u4FE1\u30E1\u30FC\u30EB\u3092 \#{sendEmail.replyEmail} \u306B\u9001\u4FE1\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.email.coordinator.ReceivedReason=\u30E6\u30FC\u30B6\u30FC\u306F '\#{sendEmail.locale.retrieveNativeName()}' \u8A00\u8A9E\u30C1\u30FC\u30E0\u306E\u30B3\u30FC\u30C7\u30A3\u30CD\u30FC\u30BF\u30FC\u3067\u3059 -jsf.email.group.maintainer.SentNotification=\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u304C \#{versionGroupJoinAction.groupName} \u30B0\u30EB\u30FC\u30D7\u306E\u30E1\u30F3\u30C6\u30CA\u30FC\u306B\u9001\u4FE1\u3055\u308C\u307E\u3057\u305F -jsf.email.maintainer.DearMaintainer=\u30B0\u30EB\u30FC\u30D7\u30E1\u30F3\u30C6\u30CA\u30FC\u306E\u65B9\u3078 -jsf.email.joingrouprequest.RequestingToJoinGroup=\ id \u304C '\#{sendEmail.fromLoginName}' \u306E Zanata \u30E6\u30FC\u30B6\u30FC '\#{sendEmail.fromName}' \u3055\u3093\u304C\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E \u30B0\u30EB\u30FC\u30D7 '\#{versionGroupJoinAction.groupName}' \u3078\u306E\u53C2\u52A0\u3092\u30EA\u30AF\u30A8\u30B9\u30C8\u3057\u3066\u3044\u307E\u3059\u3002 -jsf.email.JoinGroupRequest.ResponseInstructions=\u4EE5\u4E0B\u306E\u30EA\u30F3\u30AF\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u51E6\u7406\u3057\u307E\u3059\u3002 \u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u51E6\u7406\u3092\u5B8C\u4E86\u3057\u305F\u3089 \#{sendEmail.fromName} \u3055\u3093\u5B9B\u3066\u306E\u8FD4\u4FE1\u30E1\u30FC\u30EB\u3092 \#{sendEmail.replyEmail} \u306B\u9001\u4FE1\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -jsf.email.group.maintainer.ReceivedReason=\u30E6\u30FC\u30B6\u30FC\u306F\u30B0\u30EB\u30FC\u30D7 '\#{versionGroupJoinAction.groupName}' \u306E\u30E1\u30F3\u30C6\u30CA\u30FC\u3067\u3059 -up=\u2191 -down=\u2193 -left=\u2039 -right=\u203A -org.jboss.seam.loginFailed=\u30ED\u30B0\u30A4\u30F3\u306B\u5931\u6557\u3057\u307E\u3057\u305F -org.jboss.seam.loginSuccessful=\u3088\u3046\u3053\u305D\u3001 \#0\! -org.jboss.seam.NotLoggedIn=\u307E\u305A\u30ED\u30B0\u30A4\u30F3\u3057\u3066\u304F\u3060\u3055\u3044 -org.jboss.seam.TransactionFailed=\u30C8\u30E9\u30F3\u30B6\u30AF\u30B7\u30E7\u30F3\u304C\u5931\u6557\u3057\u307E\u3057\u305F -org.jboss.seam.NoConversation=\u4F1A\u8A71\u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\u3001 \u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u305F\u304B\u5225\u306E\u8981\u6C42\u3092\u51E6\u7406\u3057\u3066\u3044\u307E\u3057\u305F -org.jboss.seam.IllegalNavigation=\u4E0D\u6B63\u306A\u64CD\u4F5C -org.jboss.seam.ProcessEnded=\u30D7\u30ED\u30BB\u30B9 \#0 \u306F\u65E2\u306B\u7D42\u4E86\u3057\u3066\u3044\u307E\u3059 -org.jboss.seam.ProcessNotFound=\u30D7\u30ED\u30BB\u30B9 \#0 \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 -org.jboss.seam.TaskEnded=\u30BF\u30B9\u30AF \#0 \u306F\u65E2\u306B\u7D42\u4E86\u3057\u3066\u3044\u307E\u3059 -org.jboss.seam.TaskNotFound=\u30BF\u30B9\u30AF \#0 \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 -javax.faces.component.UIInput.CONVERSION=\u5024\u3092\u671F\u5F85\u3055\u308C\u305F\u30BF\u30A4\u30D7\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F -javax.faces.component.UIInput.REQUIRED=\u5024\u304C\u5FC5\u8981\u3067\u3059 -javax.faces.component.UIInput.UPDATE=\u9001\u4FE1\u3055\u308C\u305F\u60C5\u5831\u306E\u51E6\u7406\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -javax.faces.component.UISelectOne.INVALID=\u6709\u52B9\u306A\u5024\u3067\u306F\u3042\u308A\u307E\u305B\u3093 -javax.faces.component.UISelectMany.INVALID=\u6709\u52B9\u306A\u5024\u3067\u306F\u3042\u308A\u307E\u305B\u3093 -javax.faces.converter.BigDecimalConverter.DECIMAL=\u5024\u306F\u6570\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=\u5024\u306F 0 \u307E\u305F\u306F 1 \u6841\u304B\u8907\u6570\u6841\u306E\u7B26\u53F7\u306E\u4ED8\u3044\u305F 10 \u9032\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u5C0F\u6570\u70B9\u3092\u4ED8\u3051\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059 ({1} \u306A\u3069) -javax.faces.converter.BigIntegerConverter.BIGINTEGER=\u5024\u306F\u6574\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=\u5024\u306F 0 \u307E\u305F\u306F 1 \u6841\u304B\u8907\u6570\u6841\u306E\u7B26\u53F7\u306E\u4ED8\u3044\u305F\u6574\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.BooleanConverter.BOOLEAN=\u5024\u306F true \u304B false \u306E\u3044\u305A\u308C\u304B\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.BooleanConverter.BOOLEAN_detail=\u5024\u306F true \u304B false \u306E\u3044\u305A\u308C\u304B\u306B\u3057\u3066\u304F\u3060\u3055\u3044 (true \u4EE5\u5916\u306E\u5024\u306F\u3059\u3079\u3066 false \u3068\u307F\u306A\u3055\u308C\u307E\u3059) -javax.faces.converter.ByteConverter.BYTE=\u5024\u306F 0 \u304B\u3089 255 \u306E\u9593\u306E\u6570\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.ByteConverter.BYTE_detail=\u5024\u306F 0 \u304B\u3089 255 \u306E\u9593\u306E\u6570\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.CharacterConverter.CHARACTER=\u5024\u306F\u6587\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.CharacterConverter.CHARACTER_detail=\u5024\u306F\u6709\u52B9\u306A ASCII \u6587\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.DateTimeConverter.DATE=\u5024\u306F\u65E5\u4ED8\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.DateTimeConverter.DATE_detail=\u5024\u306F\u65E5\u4ED8\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3001 {1} \u306A\u3069 -javax.faces.converter.DateTimeConverter.TIME=\u5024\u306F\u6642\u9593\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.DateTimeConverter.TIME_detail=\u5024\u306F\u6642\u9593\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3001 {1} \u306A\u3069 -javax.faces.converter.DateTimeConverter.DATETIME=\u5024\u306F\u65E5\u4ED8\u3068\u6642\u523B\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.DateTimeConverter.DATETIME_detail=\u5024\u306F\u65E5\u4ED8\u3068\u6642\u523B\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3001 {1} \u306A\u3069 -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=\u5024\u3092\u5909\u63DB\u3059\u308B\u5834\u5408\u306F\u30D1\u30BF\u30FC\u30F3\u5C5E\u6027\u307E\u305F\u306F\u30BF\u30A4\u30D7\u5C5E\u6027\u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -javax.faces.converter.DoubleConverter.DOUBLE=\u5024\u306F\u6570\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.DoubleConverter.DOUBLE_detail=\u5024\u306F 4.9E-324 \u304B\u3089 1.7976931348623157E308 \u306E\u9593\u306E\u6570\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.EnumConverter.ENUM=\u5024\u306F enum \u3078\u306E\u5909\u63DB\u304C\u53EF\u80FD\u306A\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.EnumConverter.ENUM_detail=\u5024\u306F\u5B9A\u6570 {1} \u3092\u542B\u3080 enum \u3078\u306E\u5909\u63DB\u3001 \u307E\u305F\u306F enum \u304B\u3089\u306E\u5909\u63DB\u304C\u53EF\u80FD\u306A\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=\u5024\u306F enum \u3078\u306E\u5909\u63DB\u3001 \u307E\u305F\u306F enum \u304B\u3089\u306E\u5909\u63DB\u304C\u53EF\u80FD\u306A\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3001 \u305F\u3060\u3057 enum \u30AF\u30E9\u30B9\u306F\u4E0E\u3048\u307E\u305B\u3093 -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=\u5024\u306F enum \u3078\u306E\u5909\u63DB\u3001 \u307E\u305F\u306F enum \u304B\u3089\u306E\u5909\u63DB\u304C\u53EF\u80FD\u306A\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3001 \u305F\u3060\u3057 enum \u30AF\u30E9\u30B9\u306F\u4E0E\u3048\u307E\u305B\u3093 -javax.faces.converter.FloatConverter.FLOAT=\u5024\u306F\u6570\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.FloatConverter.FLOAT_detail=\u5024\u306F 1.4E-45 \u304B\u3089 3.4028235E38 \u306E\u9593\u306E\u6570\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.IntegerConverter.INTEGER=\u5024\u306F\u6574\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.IntegerConverter.INTEGER_detail=\u5024\u306F -2147483648 \u304B\u3089 2147483647 \u306E\u9593\u306E\u6574\u6570\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.LongConverter.LONG=\u5024\u306F\u6574\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.LongConverter.LONG_detail=\u5024\u306F -9223372036854775808 \u304B\u3089 9223372036854775807 \u306E\u9593\u306E\u6574\u6570\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.NumberConverter.CURRENCY=\u5024\u306F\u901A\u8CA8\u3092\u4F7F\u7528\u3057\u305F\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.NumberConverter.CURRENCY_detail=\u5024\u306F\u901A\u8CA8\u3092\u4F7F\u7528\u3057\u305F\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3001 {1} \u306A\u3069 -javax.faces.converter.NumberConverter.PERCENT=\u5024\u306F\u30D1\u30FC\u30BB\u30F3\u30C6\u30FC\u30B8\u3092\u4F7F\u3063\u305F\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.NumberConverter.PERCENT_detail=\u5024\u306F\u30D1\u30FC\u30BB\u30F3\u30C6\u30FC\u30B8\u3092\u4F7F\u3063\u305F\u5024\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3001 {1} \u306A\u3069 -javax.faces.converter.NumberConverter.NUMBER=\u5024\u306F\u6570\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.NumberConverter.NUMBER_detail=\u5024\u306F\u6570\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.NumberConverter.PATTERN=\u5024\u306F\u6570\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.NumberConverter.PATTERN_detail=\u5024\u306F\u6570\u5B57\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.ShortConverter.SHORT=\u5024\u306F\u6574\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.ShortConverter.SHORT_detail=\u5024\u306F -32768 \u304B\u3089 32767 \u306E\u9593\u306E\u6574\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.DoubleRangeValidator.MAXIMUM=\u5024\u306F {0} \u3068\u540C\u3058\u307E\u305F\u306F\u305D\u308C\u4EE5\u4E0B\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.DoubleRangeValidator.MINIMUM=\u5024\u306F {0} \u3068\u540C\u3058\u307E\u305F\u306F\u305D\u308C\u4EE5\u4E0A\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=\u5024\u306F {0} \u304B\u3089 {1} \u306E\u9593\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.DoubleRangeValidator.TYPE=\u5024\u306B\u9069\u5207\u306A\u30BF\u30A4\u30D7\u304C\u4F7F\u7528\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -javax.faces.validator.LengthValidator.MAXIMUM=\u5024\u306F {0} \u6587\u5B57\u307E\u305F\u306F\u305D\u308C\u4EE5\u4E0B\u306E\u6587\u5B57\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.LengthValidator.MINIMUM=\u5024\u306F {0} \u6587\u5B57\u307E\u305F\u306F\u305D\u308C\u4EE5\u4E0A\u306E\u6587\u5B57\u6570\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.LongRangeValidator.MAXIMUM=\u5024\u306F {0} \u3068\u540C\u3058\u307E\u305F\u306F\u305D\u308C\u4EE5\u4E0B\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.LongRangeValidator.MINIMUM=\u5024\u306F {0} \u3068\u540C\u3058\u307E\u305F\u306F\u305D\u308C\u4EE5\u4E0A\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=\u5024\u306F {0} \u304B\u3089 {1} \u306E\u9593\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.validator.LongRangeValidator.TYPE=\u5024\u306B\u9069\u5207\u306A\u30BF\u30A4\u30D7\u304C\u4F7F\u7528\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -javax.faces.validator.NOT_IN_RANGE=\u5024\u306F {0} \u304B\u3089 {1} \u306E\u9593\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -javax.faces.converter.STRING=\u5024\u3092\u6587\u5B57\u5217\u306B\u5909\u63DB\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F diff --git a/zanata-war/src/main/resources/messages_ko.properties b/zanata-war/src/main/resources/messages_ko.properties deleted file mode 100644 index 5107b3f5af..0000000000 --- a/zanata-war/src/main/resources/messages_ko.properties +++ /dev/null @@ -1,13 +0,0 @@ -jsf.Zanata=Zanata -jsf.ReadOnly=\uC77D\uAE30\uC804\uC6A9 -jsf.RecordNotFound=\uAE30\uB85D\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 -jsf.AnotherUserChangedTheSameDataPleaseTryAgain=\uB2E4\uB978 \uC0AC\uC6A9\uC790\uAC00 \uD604 \uB370\uC774\uD130\uB97C \uC218\uC815\uD558\uC600\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694. -jsf.YouDoNotHavePermissionToAccessThisResource=\uC774 \uC790\uB8CC\uB97C \uC561\uC138\uC2A4\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 -jsf.YourSessionHasTimedOutPleaseTryAgain=\uC138\uC158 \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694. -jsf.HomepageContent=\uD648\uD398\uC774\uC9C0 \uCEE8\uD150\uCE20 -jsf.projectType=\uD504\uB85C\uC81D\uD2B8 \uC720\uD615 -jsf.projectType.Description=\uD504\uB85C\uC81D\uD2B8 \uC5C5\uB85C\uB4DC\uC640 \uB2E4\uC6B4\uB85C\uB4DC\uC2DC \uD074\uB77C\uC774\uC5B8\uD2B8\uB97C \uC0AC\uC6A9\uD560 \uAC83\uC778\uC9C0 \uC6F9\uC0AC\uC774\uD2B8\uB97C \uC0AC\uC6A9\uD560 \uAC83\uC778\uC9C0 \uACB0\uC815\uD569\uB2C8\uB2E4. -jsf.projectType.DefaultBehaviour=\uD504\uB85C\uC81D\uD2B8 \uC720\uD615\uC774 \uC124\uC815\uB418\uC9C0 \uC54A\uC740 \uD504\uB85C\uC81D\uD2B8\uB294 \uAE30\uBCF8 \uC720\uD615\uC774 \uC801\uC6A9\uB429\uB2C8\uB2E4. -jsf.projectType.MoreInfo=\uC790\uC138\uD55C \uC815\uBCF4\uB294 https\://github.com/zanata/zanata/wiki/Project-Types \uD398\uC774\uC9C0\uB97C \uD655\uC778\uD558\uC2ED\uC2DC\uC624 -jsf.Projects=\uD504\uB85C\uC81D\uD2B8 -jsf.Languages=\uC5B8\uC5B4 diff --git a/zanata-war/src/main/resources/messages_tr.properties b/zanata-war/src/main/resources/messages_tr.properties deleted file mode 100644 index d2a1575ef6..0000000000 --- a/zanata-war/src/main/resources/messages_tr.properties +++ /dev/null @@ -1,140 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -up=\u2191 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -down=\u2193 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -left=\u2039 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -right=\u203A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginFailed=Oturum a\u00E7\u0131lamad\u0131 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.loginSuccessful=Ho\u015Fgeldiniz, \#0\! -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NotLoggedIn=L\u00FCtfen \u00F6ncelikle oturum a\u00E7\u0131n -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TransactionFailed=\u0130\u015Flem tamamlanamad\u0131 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.NoConversation=Konu\u015Fma sonland\u0131, zaman a\u015F\u0131m\u0131na u\u011Frad\u0131 ya da ba\u015Fka bir talebi i\u015Fliyordu -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.IllegalNavigation=Ge\u00E7ersiz y\u00F6nleme(navigasyon) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessEnded=\#0 s\u00FCreci sonlanm\u0131\u015F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.ProcessNotFound=\#0 s\u00FCreci bulunamad\u0131 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskEnded=\#0 g\u00F6revi sonlanm\u0131\u015F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -org.jboss.seam.TaskNotFound=\#0 g\u00F6revi bulunamad\u0131 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.CONVERSION=girilen de\u011Fer, beklenen tipe d\u00F6n\u00FC\u015Ft\u00FCr\u00FClemedi -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.REQUIRED=bir de\u011Fer girilmesi gereklidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UIInput.UPDATE=talebiniz i\u015Flenirken bir hata olu\u015Ftu -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectOne.INVALID=ge\u00E7erli bir de\u011Fer girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.component.UISelectMany.INVALID=ge\u00E7erli bir de\u011Fer girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL=bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=girilen de\u011Fer, s\u0131f\u0131r ya da daha fazla basamak i\u00E7eren, ondal\u0131k ayrac\u0131 ve ondal\u0131k basamak i\u00E7erebilen i\u015Faretli bir ondal\u0131k say\u0131 olmal\u0131d\u0131r, \u00F6rn. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER=bir tamsay\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=girilen de\u011Fer bir ya da daha fazla basamak i\u00E7eren bir tamsay\u0131 olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN=girilen de\u011Fer true ya da false olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.BooleanConverter.BOOLEAN_detail=girilen de\u011Fer true ya da false olmal\u0131d\u0131r (true olmayan her de\u011Fer false olarak de\u011Ferlendirilecektir) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE=girilen de\u011Fer 0 ile 255 aras\u0131nda bir say\u0131 olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ByteConverter.BYTE_detail=girilen de\u011Fer 0 ile 255 aras\u0131nda bir say\u0131 olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER=girilen de\u011Fer bir karakter olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.CharacterConverter.CHARACTER_detail=ge\u00E7erli bir ASCII karakter girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE=girilen de\u011Fer bir tarih olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATE_detail=girilen de\u011Fer bir tarih olmal\u0131d\u0131r, \u00F6rn. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME=girilen de\u011Fer bir zaman olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.TIME_detail=girilen de\u011Fer bir zaman olmal\u0131d\u0131r, \u00F6rn. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME=girilen de\u011Fer tarih ve zaman i\u00E7ermelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.DATETIME_detail=girilen de\u011Fer tarih ve zaman i\u00E7ermelidir, \u00F6rn. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=girilen de\u011Feri d\u00F6n\u00FC\u015Ft\u00FCrebilmek i\u00E7in bir desen(pattern) ya da tip \u00F6zniteli\u011Fi(attribute) tan\u0131mlanmal\u0131d\u0131r. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE=bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.DoubleConverter.DOUBLE_detail=4.9E-324 ile 1.7976931348623157E308 aras\u0131nda bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM=girilen de\u011Fer enum tipine d\u00F6n\u00FC\u015Ft\u00FCr\u00FClebilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_detail=girilen de\u011Fer sabit i\u00E7eren bir enum tipinden enum tipine d\u00F6n\u00FC\u015Ft\u00FCr\u00FClebilmelidir {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=girilen de\u011Fer enum tipinden enum tipine d\u00F6n\u00FC\u015Ft\u00FCr\u00FClebilmelidir. Ancak enum s\u0131n\u0131f\u0131(class) bulunamad\u0131 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=girilen de\u011Fer enum tipinden enum tipine d\u00F6n\u00FC\u015Ft\u00FCr\u00FClebilmelidir. Ancak enum s\u0131n\u0131f\u0131(class) bulunamad\u0131 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT=bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.FloatConverter.FLOAT_detail=1.4E-45 ile 3.4028235E38 aras\u0131nda bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER=bir tamsay\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.IntegerConverter.INTEGER_detail=-2147483648 ile 2147483647 aras\u0131nda bir tamsay\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG=bir tamsay\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.LongConverter.LONG_detail=-9223372036854775808 ile 9223372036854775807 aras\u0131nda bir tamsay\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY=para birimi tipinden bir de\u011Fer girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.CURRENCY_detail=para birimi tipinden bir de\u011Fer girilmelidir, \u00F6rn. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT=y\u00FCzdelik tipinden bir de\u011Fer girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PERCENT_detail=y\u00FCzdelik tipinden bir de\u011Fer girilmelidir, \u00F6rn. {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER=bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.NUMBER_detail=bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN=bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.NumberConverter.PATTERN_detail=bir say\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT=bir tamsay\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.ShortConverter.SHORT_detail=-32768 ile 32767 aras\u0131nda bir tamsay\u0131 girilmelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MAXIMUM=girilen de\u011Fer {0} ya da daha k\u00FC\u00E7\u00FCk olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.MINIMUM=girilen de\u011Fer {0} ya da daha b\u00FCy\u00FCk olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=girilen de\u011Fer {0} ile {1} aras\u0131nda olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.DoubleRangeValidator.TYPE=girilen de\u011Ferin tipi yanl\u0131\u015F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MAXIMUM=girilen de\u011Fer {0} ya da daha az karakter i\u00E7ermelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LengthValidator.MINIMUM=girilen de\u011Fer {0} ya da fazla karakter i\u00E7ermelidir -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MAXIMUM=girilen de\u011Fer {0} ya da daha k\u00FC\u00E7\u00FCk olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.MINIMUM=girilen de\u011Fer {0} ya da daha b\u00FCy\u00FCk olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=girilen de\u011Fer {0} ile {1} aral\u0131\u011F\u0131nda olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.LongRangeValidator.TYPE=yanl\u0131\u015F tipte bir de\u011Fer girildi -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.validator.NOT_IN_RANGE=girilen de\u011Fer {0} ile {1} aral\u0131\u011F\u0131nda olmal\u0131d\u0131r -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages -javax.faces.converter.STRING=girilen de\u011Fer bir dizgiye(string) d\u00F6n\u00FC\u015Ft\u00FCr\u00FClemedi diff --git a/zanata-war/src/main/resources/messages_uk.properties b/zanata-war/src/main/resources/messages_uk.properties deleted file mode 100644 index e7ca022eff..0000000000 --- a/zanata-war/src/main/resources/messages_uk.properties +++ /dev/null @@ -1,843 +0,0 @@ -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Zanata=Zanata -jsf.Active=\u0410\u043A\u0442\u0438\u0432\u043D\u0438\u0439 -jsf.ReadOnly=\u041B\u0438\u0448\u0435 \u0447\u0438\u0442\u0430\u043D\u043D\u044F -jsf.Obsolete=\u0417\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0435 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.RecordNotFound=\u0417\u0430\u043F\u0438\u0441 \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E -# translation auto-copied from project Zanata (obsolete, moved to zanata-server), version jsf-pages, document main/resources/messages, author Xander -jsf.DuplicatedRecord=\u041F\u043E\u0432\u0442\u043E\u0440\u043D\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AnotherUserChangedTheSameDataPleaseTryAgain=\u0406\u043D\u0448\u0438\u0439 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 \u0437\u043C\u0456\u043D\u044E\u0454 \u0442\u0456 \u0436 \u0441\u0430\u043C\u0456 \u0434\u0430\u043D\u0456. \u0411\u0443\u0434\u0442 \u043B\u0430\u0441\u043A\u0430, \u0441\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u043F\u0456\u0437\u043D\u0456\u0448\u0435. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.YouDoNotHavePermissionToAccessThisResource=\u0412\u0438 \u043D\u0435 \u043C\u0430\u0454\u0442\u0435 \u043F\u0440\u0430\u0432 \u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F \u0434\u043E \u0446\u044C\u043E\u0433\u043E \u0440\u0435\u0441\u0443\u0440\u0441\u0443. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.YourSessionHasTimedOutPleaseTryAgain=\u0427\u0430\u0441 \u0432\u0430\u0448\u043E\u0457 \u0441\u0435\u0441\u0456\u0457 \u0437\u0430\u043A\u0456\u043D\u0447\u0438\u0432\u0441\u044F. \u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0441\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0437\u043D\u043E\u0432\u0443. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Actions=\u0414\u0456\u0457 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Add=\u0414\u043E\u0434\u0430\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Cancel=\u0412\u0456\u0434\u043C\u0456\u043D\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Close=\u0417\u0430\u043A\u0440\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CreationDate=\u0414\u0430\u0442\u0430 \u0441\u0442\u0432\u043E\u0440\u0435\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Delete=\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Description=\u041E\u043F\u0438\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Edit=\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Email=Email -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Help=\u0414\u043E\u043F\u043E\u043C\u043E\u0433\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.HomepageContent=\u041A\u043E\u043D\u0442\u0435\u043D\u0442 \u0434\u043E\u043C\u0430\u0448\u043D\u044C\u043E\u0457 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Language=\u041C\u043E\u0432\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Name=\u041D\u0430\u0437\u0432\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.projectType=\u0422\u0438\u043F \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.projectType.Description=\u0412\u0438\u0437\u043D\u0430\u0447\u0430\u0454, \u044F\u043A \u043F\u0440\u043E\u0435\u043A\u0442 \u0432\u0438\u043A\u043E\u043D\u0443\u0432\u0430\u0442\u0438\u043C\u0435\u0442\u044C\u0441\u044F\: \u0447\u0435\u0440\u0435\u0437 \u0441\u043A\u0430\u0447\u0443\u0432\u0430\u043D\u043D\u044F \u0442\u0430 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0447\u0435\u0440\u0435\u0437 \u043A\u043B\u0456\u0454\u043D\u0442\u0438 \u0430\u0431\u043E \u0447\u0435\u0440\u0435\u0437 \u0441\u0430\u0439\u0442. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.projectType.DefaultBehaviour=The default type will be applied to versions under this project that do not specify their own type. -jsf.projectType.NotSpecifiedBehaviour=\u042F\u043A\u0449\u043E \u043D\u0435\u043C\u0430\u0454 \u0442\u043E\u0447\u043D\u043E \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E\u0433\u043E \u0442\u0438\u043F\u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0443, \u0442\u043E \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454\u0442\u044C\u0441\u044F \u0442\u0438\u043F, \u0449\u043E \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442 -jsf.projectType.MoreInfo=\u0414\u0435\u0442\u0430\u043B\u044C\u043D\u0443 \u0456\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0456\u044E \u043C\u043E\u0436\u043D\u0430 \u0437\u043D\u0430\u0439\u0442\u0438 \u043D\u0430 https\://github.com/zanata/zanata/wiki/Project-Types -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.projectType.NoSelection=-- \u041D\u0435 \u043E\u0431\u0440\u0430\u043D\u043E -- -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Remove=\u0412\u0438\u043B\u0443\u0447\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Save=\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Search=\u041F\u043E\u0448\u0443\u043A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Status=\u0421\u0442\u0430\u0442\u0443\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Update=\u041E\u043D\u043E\u0432\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.Upload=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u043D\u0430 \u0441\u0430\u0439\u0442 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.Username=\u0406\u043C\u2019\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Version=\u0412\u0435\u0440\u0441\u0456\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Projects=\u041F\u0440\u043E\u0435\u043A\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Groups=\u0413\u0440\u0443\u043F\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Languages=\u041C\u043E\u0432\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.More=\u0411\u0456\u043B\u044C\u0448\u0435 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.ReportAProblem=\u0414\u043E\u043F\u043E\u0432\u0456\u0441\u0442\u0438 \u043F\u0440\u043E \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.KnownIssues=\u0412\u0456\u0434\u043E\u043C\u0456 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Glossary=\u0421\u043B\u043E\u0432\u043D\u0438\u043A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Administration=\u0410\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0446\u0456\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Register=\u0420\u0435\u0454\u0441\u0442\u0440\u0430\u0446\u0456\u044F -jsf.MyProfile=\u041C\u0456\u0439 \u043F\u0440\u043E\u0444\u0456\u043B\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.SearchProjects=\u041F\u043E\u0448\u0443\u043A \u043F\u0440\u043E\u0435\u043A\u0442\u0456\u0432 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.project.search.IncludeObsoleteTooltip=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u0438 \u0437\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0456 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 \u0443 \u043F\u043E\u0448\u0443\u043A -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AboutZanata=\u041F\u0440\u043E Zanata -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Documentation=\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0456\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Wiki=\u0412\u0456\u043A\u0456 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Blog=\u0411\u043B\u043E\u0433 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Support=\u041F\u0456\u0434\u0442\u0440\u0438\u043C\u0430\u0442\u0438 -jsf.IrcHelp=IRC \u0434\u043E\u043F\u043E\u043C\u043E\u0433\u0430 -jsf.FAQ=.\u0427\u0430\u041F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.SiteMap=\u041A\u0430\u0440\u0442\u0430 \u0441\u0430\u0439\u0442\u0443 -jsf.RunningVersionInfo=\#{messages['jsf.Zanata']} \u0432\u0435\u0440\u0441\u0456\u044F \#{applicationConfiguration.version} (\#{applicationConfiguration.buildTimestamp}). -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CopyrightNotice=&\#169; 2008-12 Red Hat, Inc \u0442\u0430 \u0456\u043D\u0448\u0456. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Home=\u0414\u043E\u043C\u0456\u0432\u043A\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.server.EditHomePage.label=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u0432\u043C\u0456\u0441\u0442 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.server.EditHomePageCode.label=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u043A\u043E\u0434 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438 -jsf.server.EditHomePageCode.tooltip=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u043A\u043E\u0434\u0443 \u0434\u043E\u043C\u0430\u0448\u043D\u044C\u043E\u0457 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438 \u0456\u0441\u043D\u0443\u044E\u0447\u0456. \u041A\u043E\u0440\u0438\u0441\u043D\u043E, \u043A\u043E\u043B\u0438 \u0434\u043E\u043C\u0430\u0448\u043D\u044F \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0430 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u0437\u043C\u0456\u043D\u0435\u043D\u0430 \u0448\u043B\u044F\u0445\u043E\u043C \u0437\u043C\u0456\u043D\u0438 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.EditHomePage=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u0434\u043E\u043C\u0430\u0448\u043D\u044E \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CreateProject=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u043F\u0440\u043E\u0435\u043A\u0442 -jsf.FilterActiveProjects=\u0412\u0456\u0434\u0444\u0456\u043B\u044C\u0442\u0440\u0443\u0432\u0430\u0442\u0438 \u0430\u043A\u0442\u0438\u0432\u043D\u0456 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.FilterReadOnlyProjects=\u0412\u0456\u0434\u0444\u0456\u043B\u044C\u0442\u0440\u0443\u0432\u0430\u0442\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 \u0442\u0456\u043B\u044C\u043A\u0438 \u0434\u043B\u044F \u0447\u0438\u0442\u0430\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.FilterObsoleteProjects=\u0412\u0456\u0434\u0444\u0456\u043B\u044C\u0442\u0440\u0443\u0432\u0430\u0442\u0438 \u0441\u0442\u0430\u0440\u0456 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ProjectName=\u041D\u0430\u0437\u0432\u0430 \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.NoProjectExists=\u041F\u0440\u043E\u0435\u043A\u0442 \u043D\u0435 \u0456\u0441\u043D\u0443\u0454. -jsf.SearchResultsForProjectSearch=\u0428\u0443\u043A\u0430\u0442\u0438 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0434\u043B\u044F '\#{projectSearch.searchQuery}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.projectSearch.searchQuery.title=\u0417\u043D\u0430\u0439\u0434\u0435\u043D\u043E \#{projectSearch.resultSize} \u043F\u0440\u043E\u0435\u043A\u0442\u0456\u0432 \u0449\u043E \u0432\u0456\u0434\u043F\u043E\u0456\u0432\u0434\u0430\u044E\u0442\u044C \u0437\u0430\u043F\u0438\u0442\u0443 '\#{projectSearch.searchQuery}' -jsf.OnlyShowingFirstPagesizeResults=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438 \u043B\u0438\u0448\u0435 \u043F\u0435\u0440\u0448\u0438\u0445 \#{projectSearch.pageSize} \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0456\u0432. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CreateANewProject=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u043F\u0440\u043E\u0435\u043A\u0442 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.EditProject=\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043F\u0440\u043E\u0435\u043A\u0442 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ProjectId=ID \u041F\u0440\u043E\u0435\u043A\u0442\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ProjectIdExample=\u041D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434\: my-project -jsf.viewSourceFiles=\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u0430\u0439\u043B\u0438 \u0434\u0436\u0435\u0440\u0435\u043B -jsf.viewSourceFiles.Example=Link to human-readable source, e.g. https\://github.com/zanata/zanata -jsf.SourceCheckoutUrl=\u0414\u0436\u0435\u0440\u0435\u043B\u043E \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F\\\u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438 -jsf.SourceCheckoutUrl.Example=\u041F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u0432\u0438\u0445\u0456\u0434\u043D\u0456 \u043A\u043E\u0434\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0456 \u043A\u0435\u0440\u0443\u0432\u0430\u043D\u043D\u044F \u0432\u0435\u0440\u0441\u0456\u044F\u043C\u0438, \u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434 git@github.com\:zanata/zanata.git -jsf.customizedLocaleMessage=\u0429\u043E \u0432\u0438 \u0445\u043E\u0447\u0435\u0442\u0435 \u0434\u043E\u0434\u0430\u0442\u0438 \u0434\u043E \u0437\u043C\u0456\u043D\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\u043A\u0443 \u043C\u043E\u0432? -jsf.DisabledLocales=\u0412\u0438\u043C\u043A\u043D\u0435\u043D\u0456 \u043C\u043E\u0432\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.EnabledLocales=\u0423\u0432\u0456\u043C\u043A\u043D\u0435\u043D\u0456 \u043C\u043E\u0432\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AddLocale=\u0414\u043E\u0434\u0430\u0442\u0438 > -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.RemoveLocale=< \u0412\u0438\u043B\u0443\u0447\u0438\u0442\u0438 -jsf.RestrictRoleAccessMessage=\u0411\u0430\u0436\u0430\u0454\u0442\u0435 \u0437\u0430\u0431\u043E\u0440\u043E\u043D\u0438\u0442\u0438 \u0434\u043E\u0441\u0442\u0443\u043F \u0434\u043E \u0446\u044C\u043E\u0433\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \u043F\u0435\u0432\u043D\u0438\u043C \u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u043C? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.RestrictRoleAccessTooltip=\u041E\u0431\u043C\u0435\u0436\u0438\u0442\u0438 \u0434\u043E\u0441\u0442\u0443\u043F \u0434\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -jsf.customizedValidationMessage=\u0411\u0430\u0436\u0430\u0454\u0442\u0435 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u0442\u0438 \u043D\u0430\u043B\u0430\u0448\u0442\u043E\u0432\u0430\u043D\u0438\u0439 \u0441\u043F\u0438\u0441\u043E\u043A \u043F\u043E\u0432\u043D\u043E\u0432\u0430\u0436\u0435\u043D\u044C? -jsf.ProjectVersionId=ID \u0432\u0435\u0440\u0441\u0456\u0457 -jsf.ExportTMXAll=\u0415\u043A\u0441\u043F\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u0432\u0441\u0456 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 \u0434\u043E TMX -jsf.ConfirmExportTMXAll=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0435\u043A\u0441\u043F\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u0432\u0441\u0456 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 \u0434\u043E TMX? -jsf.ReadOnlyVersions=\u0412\u0435\u0440\u0441\u0456\u0457 \u043B\u0438\u0448\u0435 \u0434\u043B\u044F \u0447\u0438\u0442\u0430\u043D\u043D\u044F -jsf.ObsoleteVersions=\u0417\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0456 \u0432\u0435\u0440\u0441\u0456\u0457 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.DocumentCount=\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438\: -jsf.TranslateLinks=\u041F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u043D\u0430 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Translate=\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0441\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.TranslateGWTDevMode=\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0434 (GWT DevMode) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Open=\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.OpenGWTDevMode=\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 (GWT DevMode) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageVersion=\u041A\u0435\u0440\u0443\u0432\u0430\u043D\u043D\u044F \u0432\u0435\u0440\u0441\u0456\u044F\u043C\u0438 -jsf.EditVersion=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u0432\u0435\u0440\u0441\u0456\u044E -jsf.SourceDocs=\u041F\u043E\u0447. \u0434\u043E\u043A-\u0442\u0438 -jsf.SourceDocuments=\u041F\u043E\u0447\u0430\u0442\u043A\u043E\u0432\u0456 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 -# translation auto-copied from project Zanata server, version master, document zanata-war/src/main/resources/messages, author Maks -jsf.project.EditHomePage.label=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u043A\u043E\u0434 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438 -jsf.project.EditHomePage.tooltip=\u041F\u0440\u0438\u043C\u0443\u0441\u043E\u0432\u043E \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043A\u043E\u0434 \u0434\u043E\u043C\u0430\u0448\u043D\u044C\u043E\u0457 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0438. \u041A\u043E\u0440\u0438\u0441\u043D\u043E \u043A\u043E\u043B\u0438 \u0434\u043E\u043C\u0430\u0448\u043D\u044F \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0430 \u043D\u0435 \u0437\u043C\u0456\u043D\u044E\u0454\u0442\u044C\u0441\u044F \u0437\u0432\u0438\u0447\u0430\u0439\u043D\u0438\u043C\u0438 \u0441\u043F\u043E\u0441\u043E\u0431\u043E\u043C. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CreateVersion=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0432\u0435\u0440\u0441\u0456\u044E -jsf.ManageMaintainers=\u041A\u0435\u0440\u0443\u0432\u0430\u043D\u043D\u044F \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0430\u043C\u0438 -jsf.CopyTrans=\u041A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0438 -jsf.project.CopyTransOpts.tooltip=\u0412\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0438 \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u0456 \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F \u0434\u043B\u044F \#{messages['jsf.CopyTrans']}. -jsf.ProjectMaintainers=\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -jsf.NoMaintainers=(\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0456\u0432 \u043D\u0435 \u043F\u0440\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E) -jsf.project.RoleRestrictions=\u041E\u0431\u043C\u0435\u0436\u0435\u043D\u043D\u044F \u0440\u0456\u0432\u043D\u0456\u0432 -jsf.project.ProjectRestrictedToFollowingRoles=\u0426\u0435\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u043E\u0431\u043C\u0435\u0436\u0438\u0432 \u0434\u043E\u0441\u0442\u0443\u043F \u0434\u043B\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0456\u0432 \u0442\u0430\u043A\u0438\u0445 \u0440\u0456\u0432\u043D\u0456\u0432\: -jsf.ExportTMXProject=\u0415\u043A\u0441\u043F\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u043F\u0440\u043E\u0435\u043A\u0442 \u0434\u043E TMX -jsf.ConfirmExportTMXProject=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0435\u043A\u0441\u043F\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u043F\u043E\u0442\u043E\u0447\u043D\u0438\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u0434\u043E TMX? -jsf.AddProjectMaintainer=\u0414\u043E\u0434\u0430\u0442\u0438 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0430 \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -jsf.AreYouSureYouWishToRemoveThisPersonAsProjectMaintainer=\u0412\u0438 \u0434\u0456\u0439\u0441\u043D\u043E \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u0434\u0430\u043B\u0438 \u0446\u044E \u043B\u044E\u0434\u0438\u043D\u0443 \u0437\u0456 \u0441\u043F\u0438\u0441\u043A\u0443 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0456\u0432 \u043F\u0440\u043E\u0435\u043A\u0442\u0443? -jsf.AddGroupMaintainer=\u0414\u043E\u0434\u0430\u0442\u0438 \u0433\u0440\u0443\u043F\u043E\u0432\u043E\u0433\u043E \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0430 -jsf.AreYouSureYouWishToRemoveThisPersonAsGroupMaintainer=\u0412\u0438 \u0432\u043F\u0435\u0432\u043D\u0435\u043D\u0456, \u0449\u043E \u0431\u0430\u0436\u0430\u0454\u0442\u0435 \u0432\u0438\u043A\u043B\u044E\u0447\u0438\u0442\u0438 \u0446\u044E \u043E\u0441\u043E\u0431\u0443 \u0437 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0456\u0432 \u0433\u0440\u0443\u043F\u0438? -jsf.YouAreNoLongerMaintainerForThisProject=\u0412\u0438 \u0431\u0456\u043B\u044C\u0448\u0435 \u043D\u0435 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440 \u0446\u044C\u043E\u0433\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443. -jsf.project.CopyTransOpts.title=\#{messages['jsf.CopyTrans']} \u041E\u043F\u0446\u0456\u0457 -jsf.project.CopyTransOpts.saved=\#{messages['jsf.CopyTrans']} \u043E\u043F\u0446\u0456\u0457 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043E. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.pageTitle=\#{messages['jsf.CopyTrans']} \u0434\u043B\u044F \#{viewAllStatusAction.projectSlug}\:\#{viewAllStatusAction.iterationSlug} -jsf.iteration.CopyTrans.Condition=\u0421\u0442\u0430\u043D -jsf.iteration.CopyTrans.Condition.onContentMismatch=\u0423 \u0440\u0430\u0437\u0456 \u043D\u0435\u0441\u043F\u0456\u0432\u043F\u0430\u0434\u0456\u043D\u043D\u044F \u0432\u043C\u0456\u0441\u0442\u0443\: -jsf.iteration.CopyTrans.Condition.onProjectMismatch=\u0423 \u0440\u0430\u0437\u0456 \u043D\u0435\u0441\u043F\u0456\u0432\u043F\u0430\u0434\u0456\u043D\u043D\u044F \u043F\u0440\u043E\u0435\u043A\u0442\u0443\: -jsf.iteration.CopyTrans.Condition.onContextMismatch=\u0423 \u0440\u0430\u0437\u0456 \u043D\u0435\u0441\u043F\u0456\u0432\u043F\u0430\u0434\u0456\u043D\u043D\u044F \u0432\u043C\u0456\u0441\u0442\u0443 (resId, msgctxt)\: -jsf.iteration.CopyTrans.Condition.onDocIdMismatch=\u0423 \u0440\u0430\u0437\u0456 \u043D\u0435\u0441\u043F\u0456\u0432\u043F\u0430\u0434\u0456\u043D\u043D\u044F ID \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0443 (\u043D\u0430\u0437\u0432\u0430 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0443 \u0442\u0430 \u0448\u043B\u044F\u0445)\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.Condition.final=\u0406\u043D\u0430\u043A\u0448\u0435\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.Action=\u0414\u0456\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.Action.reject=\u0412\u0456\u0434\u0445\u0438\u043B\u0438\u0442\u0438 -jsf.iteration.CopyTrans.Help.reject=\u0412\u0456\u0434\u0445\u0438\u043B\u0438\u0442\u0438 \u0456 \u043D\u0435 \u043A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434. -jsf.iteration.CopyTrans.Help.downgradeToFuzzy=\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0434 \u0440\u043E\u0437\u0433\u043B\u044F\u0434\u0430\u0454\u0442\u044C\u0441\u044F \u0434\u043B\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u0433\u043E \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F \u0443 \u044F\u043A\u043E\u0441\u0442\u0456 \u0441\u043F\u0456\u0440\u043D\u043E\u0433\u043E. \u041F\u0435\u0440\u0435\u0432\u0456\u0440\u044F\u0442\u0438\u043C\u0443\u0442\u044C\u0441\u044F \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u043D\u0456 \u0443\u043C\u043E\u0432\u0438. -jsf.iteration.CopyTrans.Action.short.downgradeToFuzzy=\u041F\u043E\u0442\u0440\u0456\u0431\u0435\u043D \u043E\u0433\u043B\u044F\u0434 -jsf.iteration.CopyTrans.Action.ignore=\u041D\u0435 \u0437\u0432\u0430\u0436\u0430\u0442\u0438 -jsf.iteration.CopyTrans.Action.short.ignore=\u041D\u0435 \u0437\u0432\u0430\u0436\u0430\u0442\u0438 -jsf.iteration.CopyTrans.Help.ignore=\u0426\u044F \u0443\u043C\u043E\u0432\u0430 \u043D\u0435 \u0431\u0440\u0430\u0442\u0438\u043C\u0435\u0442\u044C\u0441\u044F \u0434\u043E \u0443\u0432\u0430\u0433\u0438 \u043F\u0440\u0438 \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u0456 \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u0433\u043E \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443. -# translation auto-copied from project Publican, version 3, document publican -jsf.Translated=\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0435\u043D\u043E -jsf.iteration.CopyTrans.Help.translated=\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0434 \u0431\u0443\u0434\u0435 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043E \u0456 \u043F\u043E\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u044F\u043A /"\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0435\u043D\u043E/", \u044F\u043A\u0449\u043E \u0432\u0456\u043D \u043D\u0435 \u0431\u0443\u0432 \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D\u0438\u0439 \u0447\u0438 \u043F\u043E\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u044F\u043A /"\u0421\u0443\u043C\u043D\u0456\u0432\u043D\u0438\u0439/" -jsf.Start=\u0421\u0442\u0430\u0440\u0442 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.AlreadyStarted=\#{messages['jsf.CopyTrans']} \u0432\u0436\u0435 \u0440\u043E\u0437\u043F\u043E\u0447\u0430\u0442\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0435\u043C \#{copyTransManager.getCopyTransProcessHandle( copyTransAction.projectIteration ).triggeredBy} \u0434\u043B\u044F \u0432\u0435\u0440\u0441\u0456\u0457 \#{copyTransAction.projectIteration.slug} \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \#{copyTransAction.projectIteration.project.name}. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CopyTrans.ClickHereToViewProgress=\u041D\u0430\u0442\u0438\u0441\u043D\u0456\u0442\u044C \u0442\u0443\u0442 \u0449\u043E\u0431 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u043F\u0440\u043E\u0433\u0440\u0435\u0441. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.AlreadyStarted.flash=\u0425\u0442\u043E\u0441\u044C \u0456\u043D\u0448\u0438\u0439 \u0440\u043E\u0437\u043F\u043E\u0447\u0430\u0432 \#{messages['jsf.CopyTrans']} \u0434\u043B\u044F \u0446\u0456\u0454\u0457 \u0432\u0435\u0440\u0441\u0456\u0457. -jsf.iteration.CopyTrans.NoDocuments=\u041D\u0435\u043C\u0430\u0454 \u0436\u043E\u0434\u043D\u043E\u0433\u043E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0443 \u0432 \u0446\u0456\u0439 \u0432\u0435\u0440\u0441\u0456\u0457 \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.Started=\#{messages['jsf.CopyTrans']} \u0440\u043E\u0437\u043F\u043E\u0447\u0430\u0442\u043E. -jsf.iteration.ShowAllLocales.title=\u0412\u0430\u0448\u0456 \u043A\u043E\u043C\u0430\u043D\u0434\u0438 \u0431\u0443\u0434\u0443\u0442\u044C \u043F\u0456\u0434\u0441\u0432\u0456\u0447\u0435\u043D\u0456 \u043D\u0438\u0449\u0435. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Refresh=\u041E\u043D\u043E\u0432\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.RefreshTable=\u041E\u043D\u043E\u0432\u0438\u0442\u0438 \u0442\u0430\u0431\u043B\u0438\u0446\u044E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.stats.OpenInWebEditor=\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0432 \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\u0456 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Documents=\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Statistics=\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430 -jsf.ByWords=\u0417\u0430 \u0441\u043B\u043E\u0432\u0430\u043C\u0438 -jsf.Message=\u0417\u0430 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.stats.Total=\u0417\u0430\u0433\u0430\u043B\u043E\u043C\: -jsf.stats.Approved=\u0417\u0430\u0442\u0432\u0435\u0440\u0434\u0436\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.stats.Translated=\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\: -jsf.stats.Draft=\u0427\u043E\u0440\u043D\u043E\u0432\u0438\u043A\: -jsf.stats.Untranslated=\u041D\u0435\u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0435\u043D\u043E\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.stats.ShortHoursSuffix=\u0433\u043E\u0434\u0438\u043D -jsf.NoContent=(No Content) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.LastTranslated=\u041E\u0441\u0442\u0430\u043D\u043D\u0456\u0439 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ConfigFile=\u0424\u0430\u0439\u043B \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.GenerateProjectConfig=\u0417\u0433\u0435\u043D\u0435\u0440\u0443\u0432\u0430\u0442\u0438 \u0444\u0430\u0439\u043B \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0443 (zanata.xml) -jsf.iteration.CopyTrans=\u041A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0438 -jsf.iteration.CopyTrans.title=\u0421\u043A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u0435\u043D\u0438\u0439 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434 \u0437 \u0456\u043D\u0448\u043E\u0433\u043E \u0441\u0445\u043E\u0436\u043E\u0433\u043E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0443. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.JoinedGroups=\u041E\u0431\u2019\u0454\u0434\u043D\u0430\u043D\u0456 \u0433\u0440\u0443\u043F\u0438 -jsf.iteration.CopyTrans.inProgress=\u0412\u0438\u043A\u043E\u043D\u0443\u0454\u0442\u044C\u0441\u044F \#{messages['jsf.CopyTrans']} ... -jsf.iteration.CopyTrans.started=\u0420\u043E\u0437\u043F\u043E\u0447\u0430\u0442\u043E \#{viewAllStatusAction.copyTransStartTime} \u0442\u043E\u043C\u0443 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0435\u043C \#{pHandle.triggeredBy} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.CopyTrans.estimatedTimeRemaining=\u041B\u0438\u0448\u0438\u043B\u043E\u0441\u044C \u0447\u0430\u0441\u0443\: \#{viewAllStatusAction.copyTransEstimatedTimeLeft} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.requireTranslationReview=\u041F\u043E\u0442\u0440\u0435\u0431\u0443\u0454 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443 -jsf.group.FindGroup=\u0417\u043D\u0430\u0439\u0442\u0438 \u0433\u0440\u0443\u043F\u0443 -jsf.NoResultToDisplay=\u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0456\u0432 \u043D\u0435\u043C\u0430\u0454 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.GroupName=\u041D\u0430\u0437\u0432\u0430 \u0433\u0440\u0443\u043F\u0438 -jsf.SelectGroup=\u041E\u0431\u0440\u0430\u0442\u0438 \u0433\u0440\u0443\u043F\u0443 -jsf.Select=\u041E\u0431\u0440\u0430\u0442\u0438 -jsf.ExportTMX=\u0415\u043A\u0441\u043F\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 TMX -jsf.ExportTMXIter=\u0415\u043A\u0441\u043F\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u043F\u043E\u0442\u043E\u0447\u043D\u0443 \u0432\u0435\u0440\u0441\u0456\u044E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \u0434\u043E TMX -jsf.ConfirmExportTMXIter=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0435\u043A\u0441\u043F\u043E\u0440\u0442\u0443\u0432\u0430\u0442\u0438 \u043F\u043E\u0442\u043E\u0447\u043D\u0443 \u0432\u0435\u0440\u0441\u0456\u044E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \u0434\u043E TMX? -jsf.pager.NextPage=\u043D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0439 -jsf.pager.PreviousPage=\u043F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0456\u0439 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.NoFiles=\u0424\u0430\u0439\u043B\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.Path=\u0428\u043B\u044F\u0445 -jsf.iteration.files.Filter.title=\u0424\u0456\u043B\u044C\u0442\u0440\u0443\u0432\u0430\u0442\u0438 \u0437\u0430 \u043D\u0430\u0437\u0432\u043E\u044E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430 -jsf.Upload.Title=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0449\u043E\u0431 \u043E\u0431\u2019\u0454\u0434\u043D\u0430\u0442\u0438/\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0438\u0441\u0430\u0442\u0438 \u043F\u043E\u0442\u043E\u0447\u043D\u0438\u0439 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434 -jsf.iteration.files.UploadFile=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B -jsf.iteration.files.Merge=\u041E\u0431\u2019\u0454\u0434\u043D\u0430\u0442\u0438 -jsf.iteration.files.Merge.title=\u042F\u043A\u0449\u043E \u043F\u043E\u0437\u043D\u0430\u0447\u0435\u043D\u043E, \u043F\u043E\u0442\u043E\u0447\u043D\u0456 \u0434\u0430\u043D\u0456 \u0431\u0443\u0434\u0443\u0442\u044C \u043E\u0431\u2019\u0454\u0434\u043D\u0430\u043D\u0456 \u0456\u0437 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u0438\u043C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043C. \u0412 \u0456\u043D\u0448\u043E\u043C\u0443 \u0432\u0438\u043F\u0430\u0434\u043A\u0443 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0431\u0443\u0434\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u043F\u043E\u0432\u0435\u0440\u0445 \u0456\u0441\u043D\u0443\u044E\u0447\u0438\u0445 \u0434\u0430\u043D\u0438\u0445. -jsf.iteration.files.MergeCheckbox.Title=\u042F\u043A\u0449\u043E \u043F\u043E\u0437\u043D\u0430\u0447\u0435\u043D\u043E, \u043E\u043D\u043E\u0432\u043B\u0435\u043D\u0456 \u0440\u044F\u0434\u043A\u0438 \u0431\u0443\u0434\u0443\u0442\u044C \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u0456, \u0432\u0441\u0456 \u0456\u043D\u0448\u0456 \u0437\u0430\u043B\u0438\u0448\u0430\u0442\u044C\u0441\u044F \u0431\u0435\u0437 \u0437\u043C\u0456\u043D. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.Download=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.dotpot=.pot -jsf.iteration.files.dotofflinepot=\u0430\u0432\u0442\u043E\u043D\u043E\u043C\u043D\u0438\u0439 .pot -jsf.iteration.files.dotofflinepot.description=\u0421\u043F\u0435\u0446\u0456\u0430\u043B\u044C\u043D\u0438\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 pot \u044F\u043A\u0438\u0439 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454 msgctxt \u0434\u043B\u044F \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F Zanata id. -jsf.iteration.files.dotofflinepot.purpose=\u0426\u0435 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454\u0442\u044C\u0441\u044F \u0432\u0438\u043A\u043B\u044E\u0447\u043D\u043E \u0434\u043B\u044F \u0430\u0432\u0442\u043E\u043D\u043E\u043C\u043D\u043E\u0433\u043E \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443. \u0432\u0438\u0445\u0456\u0434\u043D\u0456 \u0444\u0430\u0439\u043B\u0438 \u043D\u0435 \u0441\u043B\u0456\u0434 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0443\u0432\u0430\u0442\u0438 \u0432 \u0446\u044C\u043E\u043C\u0443 \u0444\u043E\u0440\u043C\u0430\u0442\u0456. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.dotpo=.po -jsf.iteration.files.dotofflinepo=\u0430\u0432\u0442\u043E\u043D\u043E\u043C\u043D\u0438\u0439 .po -jsf.iteration.files.dotofflinepo.description=\u0421\u043F\u0435\u0446\u0456\u0430\u043B\u044C\u043D\u0438\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 po \u044F\u043A\u0438\u0439 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454 msgctxt \u0434\u043B\u044F \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F Zanata id. -jsf.iteration.files.dotofflinepo.purpose=Zanata \u0432\u0438\u043C\u0430\u0433\u0430\u0454, \u0449\u043E\u0431 \u0444\u0430\u0439\u043B\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443, \u044F\u043A\u0456 \u043F\u043E\u0447\u0430\u0442\u043A\u043E\u0432\u043E \u043D\u0435 \u0431\u0443\u043B\u0438 \u0443 \u0444\u043E\u0440\u043C\u0430\u0442\u0456 .po, \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0443\u0432\u0430\u043B\u0438\u0441\u044F \u0441\u0430\u043C\u0435 \u0432 \u0442\u0430\u043A\u043E\u043C\u0443 \u0444\u043E\u0440\u043C\u0430\u0442\u0456. -jsf.iteration.files.ConfirmDocDeletion=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0446\u0435\u0439 \u043F\u043E\u0447\u0430\u0442\u043A\u043E\u0432\u0438\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.DocumentDeleted=\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0443\u0441\u043F\u0456\u0448\u043D\u043E \u0432\u0438\u0434\u0430\u043B\u0435\u043D\u043E. -jsf.iteration.files.ProcessDlgTitle=\u041E\u0431\u0440\u043E\u0431\u043A\u0430 \u0444\u0430\u0439\u043B\u0456\u0432 \u043F\u0440\u043E\u0435\u043A\u0442\u0443... -jsf.iteration.files.UploadDocument=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.SupportedUploadFormats=\u041F\u0456\u0434\u0442\u0440\u0438\u043C\u0443\u0432\u0430\u043D\u0456 \u0444\u043E\u0440\u043C\u0430\u0442\u0438\: .pot .dtd .txt .odt .fodt .odp .fodp .ods .fods .odg .fodg .odb .odf -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.SourceLanguage=\u041C\u043E\u0432\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.DocumentPath=\u0428\u043B\u044F\u0445 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0443 -jsf.iteration.files.CustomParams=\u0412\u043B\u0430\u0441\u043D\u0456 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0438 \u0440\u043E\u0437\u0431\u043E\u0440\u0443 -jsf.iteration.files.CustomParams.description=\u0412\u043B\u0430\u0441\u043D\u0456 \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0438 \u041F\u0430\u0440\u0441\u0438\u043D\u0433\u0443 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u044E\u0442\u044C\u0441\u044F \u0434\u043B\u044F \u0437\u043C\u0456\u043D\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0456\u0432 \u043E\u0431\u0440\u043E\u0431\u043A\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430. -jsf.iteration.files.CustomParams.linkText=\u0421\u0442\u043E\u0440\u0456\u043D\u043A\u0430 \u0456\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0456\u0457 \u043F\u0440\u043E \u0412\u043B\u0430\u0441\u043D\u0456 \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0438 \u041F\u0430\u0440\u0441\u0438\u043D\u0433\u0443 -jsf.ConfigFileForOfflineTranslation=\u0424\u0430\u0439\u043B \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u044C \u0430\u0432\u0442\u043E\u043D\u043E\u043C\u043D\u043E\u0433\u043E \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443 -jsf.GenerateProjectConfigSingleLocale=\u0413\u0435\u043D\u0435\u0440\u0443\u0432\u0430\u0442\u0438 \u0444\u0430\u0439\u043B \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0443 (zanata.xml) \u0434\u043B\u044F \u0446\u0456\u0454\u0457 \u0432\u0435\u0440\u0441\u0456\u0457 \u0437 \u043C\u043E\u0432\u043E\u044E \#{projectIterationFilesAction.localeId} -jsf.GenerateProjectConfigForOfflineTranslation=\u0417\u0433\u0435\u043D\u0435\u0440\u0443\u0432\u0430\u0442\u0438 \u0444\u0430\u0439\u043B \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0443 (zanata.xml) \u0434\u043B\u044F \u0446\u0456\u0454\u0457 \u0432\u0435\u0440\u0441\u0456\u0457 \u0437 \u043C\u043E\u0432\u043E\u044E \#{projectIterationFilesAction.localeId}, \u0437 \u0442\u0438\u043F\u043E\u043C \u043F\u0440\u043E\u0435\u043A\u0442\u0443 'offlinepo' \u0434\u043B\u044F \u0430\u0432\u0442\u043E\u043D\u043E\u043C\u043D\u043E\u0433\u043E \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443 po-\u0444\u0430\u0439\u043B\u0456\u0432. -jsf.ConfigFileDisabledProjectNotSet=\u0412\u0438\u043C\u043A\u043D\u0435\u043D\u043E, \u043E\u0441\u043A\u0456\u043B\u044C\u043A\u0438 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440 \u043D\u0435 \u0432\u043A\u0430\u0437\u0430\u0432 \u0442\u0438\u043F \u0446\u044C\u043E\u0433\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.DownloadAllFiles=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0432\u0441\u0435 (zip) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.DownloadAllFiles.title=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0432\u0441\u0456 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0435\u043D\u0456 \u0444\u0430\u0439\u043B\u0438. -jsf.iteration.files.DownloadAllFilesOfflinePo=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0432\u0441\u0435 (\u0430\u0432\u0442\u043E\u043D\u043E\u043C\u043D\u0438\u0439 po zip) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.DownloadAllFilesOfflinePo.title=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0432\u0441\u0456 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0435\u043D\u0456 \u0444\u0430\u0439\u0434\u0438 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0456 po \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443 \u043E\u0444\u043B\u0430\u0439\u043D. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed=\u041F\u0440\u043E\u0435\u043A\u0442 \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u0442\u0438\u043F 'Gettext' \u0430\u0431\u043E 'Podir'. \u0417\u0432\u2019\u044F\u0436\u0456\u0442\u044C\u0441\u044F \u0437 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u043E\u043C \u043F\u0440\u043E\u0435\u043A\u0442\u0443. -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotSet=\u041D\u0435 \u0432\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E \u0442\u0438\u043F \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \u0434\u043B\u044F \u0442\u0430\u043A\u043E\u0457 \u0437\u043C\u0456\u043D\u0438. \u0421\u043A\u043E\u043D\u0442\u0430\u043A\u0442\u0443\u0439\u0442\u0435\u0441\u044F \u0437 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u043E\u043C \u043F\u0440\u043E\u0435\u043A\u0442\u0443. -jsf.iteration.files.ConfirmDownloadAllFiles=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u043F\u0456\u0434\u0433\u043E\u0442\u0443\u0454\u0442\u044C\u0441\u044F \u0437\u0430 \u043A\u0456\u043B\u044C\u043A\u0430 \u0445\u0432\u0438\u043B\u0438\u043D. \u0413\u0430\u0440\u0430\u0437\u0434? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.generatezip.ProgressLabel=\#{projectIterationZipFileAction.zipFilePrepHandle.currentProgress} \u0437 \#{projectIterationZipFileAction.zipFilePrepHandle.maxProgress} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.WhyCantITranslate=\u0427\u043E\u043C\u0443 \u044F \u043D\u0435 \u043C\u043E\u0436\u0443 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0442\u0438? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.translateDenied.NotLoggedIn=\u0412\u0438 \u043D\u0435 \u0443\u0432\u0456\u0439\u0448\u043B\u0438. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.iteration.files.translateDenied.VersionIsReadOnly=\u0426\u044F \u0432\u0435\u0440\u0441\u0456\u044F \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \u0442\u0456\u043B\u044C\u043A\u0438 \u0434\u043B\u044F \u0447\u0438\u0442\u0430\u043D\u043D\u044F. -jsf.iteration.files.translateDenied.VersionIsObsolete=\u0426\u044F \u0432\u0435\u0440\u0441\u0456\u044F \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \u0437\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0430 -jsf.iteration.files.translateDenied.UserNotInProjectRole=\u0429\u043E\u0431 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0442\u0438 \u0446\u0435\u0439 \u043F\u0440\u043E\u0435\u043A\u0442, \u0432\u0438 \u043F\u043E\u0432\u0438\u043D\u043D\u0456 \u0431\u0443\u0442\u0438 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0435\u043C \u0442\u0430\u043A\u043E\u0433\u043E \u0440\u0456\u0432\u043D\u044F\: {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.NoGroupExists=\u0413\u0440\u0443\u043F\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456. -jsf.groups.ShowActiveGroups=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438 \u0430\u043A\u0442\u0438\u0432\u043D\u0456 \u0433\u0440\u0443\u043F\u0438 -jsf.groups.ShowObsoleteGroups=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438 \u0437\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0456 \u0433\u0440\u0443\u043F\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.GroupId=ID \u0413\u0440\u0443\u043F\u0438 -jsf.GroupIdExample=\u041D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434\: moya-grupa -jsf.AddProjectVersions=\u0414\u043E\u0434\u0430\u0442\u0438 \u0432\u0435\u0440\u0441\u0456\u0457 \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -jsf.groups.FindProjectVersion=\u0417\u043D\u0430\u0439\u0442\u0438 \u0432\u0435\u0440\u0441\u0456\u044E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -jsf.NoResultToDisplayProjectSearch=\u041D\u0456\u0447\u043E\u0433\u043E \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E. \u041F\u0435\u0440\u0435\u0432\u0456\u0440\u0442\u0435, \u0431\u0443\u043B\u044C \u043B\u0430\u0441\u043A\u0430, \u0447\u0438 \u0448\u0443\u043A\u0430\u043D\u0438\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u043C\u0430\u0454 \u0432\u0435\u0440\u0441\u0456\u0457. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageSearch.SelectAll=\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u0432\u0441\u0435 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AddSelected=\u0414\u043E\u0434\u0430\u0442\u0438 \u0432\u0438\u0431\u0440\u0430\u043D\u0435 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.EditGroup=\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u0433\u0440\u0443\u043F\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.GroupMaintainers=\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0438 \u0433\u0440\u0443\u043F\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CreateSupportedLanguage=\u0414\u043E\u0434\u0430\u0442\u0438 \u043D\u043E\u0432\u0443 \u043C\u043E\u0432\u0443 -jsf.NativeName=\u041F\u043E\u0447\u0430\u0442\u043A\u043E\u0432\u0430 \u043D\u0430\u0437\u0432\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Members=\u0423\u0447\u0430\u0441\u043D\u0438\u043A\u0438 -jsf.LanguageTeamTitle=\u041A\u043E\u043C\u0430\u043D\u0434\u0430 \#{languageTeamAction.locale.retrieveDisplayName()} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.SizeMembers=\#{languageTeamAction.locale.members.size} \u0443\u0447\u0430\u0441\u043D\u0438\u043A\u0456\u0432 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Coordinator=\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.JoinLanguageTeam=\u041F\u0440\u0438\u0454\u0434\u043D\u0430\u0442\u0438\u0441\u044C \u0434\u043E \u043A\u043E\u043C\u0430\u043D\u0434\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.LeaveLanguageTeam=\u041F\u043E\u043A\u0438\u043D\u0443\u0442\u0438 \u043A\u043E\u043C\u0430\u043D\u0434\u0443 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.RequestToJoinLanguageTeam=\u0417\u0430\u043F\u0438\u0442 \u043D\u0430 \u0432\u0441\u0442\u0443\u043F \u0434\u043E \u043A\u043E\u043C\u0430\u043D\u0434\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.contactLanguageTeamCoordinator=\u0417\u0432\u2019\u044F\u0437\u043E\u043A \u0437 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u043E\u043C \u043A\u043E\u043C\u0430\u043D\u0434\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AddTeamMember=\u0414\u043E\u0434\u0430\u0442\u0438 \u0443\u0447\u0430\u0441\u043D\u0438\u043A\u0430 -jsf.FindUsersToAdd=\u0417\u043D\u0430\u0439\u0442\u0438 \u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0456\u0432 \u0434\u043B\u044F \u041F\u0440\u0438\u0454\u0434\u043D\u0430\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AlreadyInTeam=\u0412\u0436\u0435 \u0432 \u043A\u043E\u043C\u0430\u043D\u0434\u0456 -jsf.EditHelpPageContent=\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u0412\u043C\u0456\u0441\u0442 \u0414\u043E\u0432\u0456\u0434\u043A\u0438 -jsf.ContactAdmin=\u0417\u0432\u2019\u044F\u0437\u0430\u0442\u0438\u0441\u044C \u0437 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C -jsf.Entries=\u0417\u0430\u043F\u0438\u0441\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Glossary.supportedFileFormat=\u041F\u0456\u0434\u0442\u0440\u0438\u043C\u0443\u0432\u0430\u043D\u0456 \u0444\u043E\u0440\u043C\u0430\u0442\u0438 \u0444\u0430\u0439\u043B\u0456\u0432\: PO \u0442\u0430 CSV -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Glossary.SourceLocale.Title=\u041C\u043E\u0432\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 (\u0432\u0456\u0434\u043D\u043E\u0441\u0438\u0442\u044C\u0441\u044F \u0442\u0456\u043B\u044C\u043A\u0438 \u0434\u043E \u0444\u043E\u0440\u043C\u0430\u0442\u0443 \u0444\u0430\u0439\u043B\u0456\u0432 PO) -jsf.TargetLanguage=\u0426\u0456\u043B\u044C\u043E\u0432\u0430 \u043C\u043E\u0432\u0430 -jsf.Glossary.TargetLocale.Title=\u0426\u0456\u043B\u044C\u0432\u0430 \u043C\u043E\u0432\u0430 (\u0432\u0456\u0434\u043D\u043E\u0441\u0438\u0442\u044C\u0441\u044F \u0442\u0456\u043B\u044C\u043A\u0438 \u0434\u043E \u0444\u043E\u0440\u043C\u0430\u0442\u0443 \u0444\u0430\u0439\u043B\u0456\u0432 PO) -jsf.Glossary.TreatSourceCommentsAsTarget=\u0412\u0432\u0430\u0436\u0430\u0442\u0438 \u0432\u0438\u0445\u0456\u0434\u043D\u0456 \u043A\u043E\u043C\u0435\u043D\u0442\u0430\u0440\u0456 \u0456 \u043F\u0440\u0438\u043C\u0456\u0442\u043A\u0438 \u0437\u0430 \u0446\u0456\u043B\u044C\u043E\u0432\u0456 \u043A\u043E\u043C\u0435\u043D\u0442\u0430\u0440\u0456? -jsf.Glossary.TreatSourceCommentsAsTarget.Title=\u0412\u0456\u0434\u0437\u043D\u0430\u0447\u0442\u0435, \u0449\u043E\u0431 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u0442\u0438 \u0432\u0438\u0445\u0456\u0434\u043D\u0456 \u043A\u043E\u043C\u0435\u043D\u0442\u0430\u0440\u0456 \u0442\u0430 \u043F\u0440\u0438\u043C\u0456\u0442\u043A\u0438 \u044F\u043A \u0446\u0456\u043B\u044C\u043E\u0432\u0456 \u043A\u043E\u043C\u0435\u043D\u0442\u0430\u0440\u0456. -jsf.Glossary.CommentColumnNames.Title=\u0421\u043F\u0435\u0446\u0456\u0430\u043B\u044C\u043D\u0456 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438 \u0441\u0442\u043E\u0432\u043F\u0446\u044F \u043A\u043E\u043C\u0435\u043D\u0442\u0430\u0440\u0456\u0432 \u0434\u043B\u044F \u0444\u043E\u0440\u043C\u0430\u0442\u0443 \u0444\u0430\u0439\u043B\u0456\u0432 csv. CSV \u0444\u043E\u0440\u043C\u0430\u0442\: {source locale},{locale1},{locale2},...,{pos},{description} \u0410\u0411\u041E {source locale},{locale},{locale},...,{description1},{description2},... (\u0432\u0456\u0434\u043D\u043E\u0441\u0438\u0442\u044C\u0441\u044F \u0442\u0456\u043B\u044C\u043A\u0438 \u0434\u043E \u0444\u043E\u0440\u043C\u0430\u0442\u0443 \u0444\u0430\u0439\u043B\u0456\u0432 CSV) -jsf.ThisActionCannotBeUndone=\u0426\u044E \u0434\u0456\u044E \u043D\u0435\u043C\u043E\u0436\u043B\u0438\u0432\u043E \u0432\u0456\u0434\u043C\u0456\u043D\u0438\u0442\u0438. -jsf.SelectLocaleToDelete=\u0412\u0438\u0431\u0435\u0440\u0456\u0442\u044C \u043C\u043E\u0432\u0443 \u0434\u043B\u044F \u0432\u0438\u043B\u0443\u0447\u0435\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.SignUp=\u0417\u0430\u0439\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.NameToolTip=\u0412 \u0456\u043C\u0435\u043D\u0456 \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432\u0435\u043B\u0438\u043A\u043E\u044E \u043F\u0435\u0440\u0448\u0430 \u0431\u0443\u043A\u0432\u0430. -jsf.EmailToolTip=E-mail \u0430\u0434\u0440\u0435\u0441\u0430 \u043C\u0430\u0454 \u0442\u0443\u0442\u0438 \u0443 \u0444\u043E\u0440\u043C\u0430\u0442\u0456 username@domain.name. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.UsernameToolTip=\u0406\u043C\u2019\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432 \u043D\u0438\u0436\u043D\u044C\u043E\u043C\u0443 \u0440\u0435\u0433\u0456\u0441\u0442\u0440\u0456. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Password=\u041F\u0430\u0440\u043E\u043B\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ConfirmPassword=\u041F\u043E\u0432\u0442\u043E\u0440\u0456\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.IAgreeToThe=\u042F \u043F\u043E\u0433\u043E\u0434\u0436\u0443\u044E\u0441\u044C \u0437 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.TermsOfUse=\u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C\u0438 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u043D\u043D\u044F -jsf.register.LoginUsingOpenId=\u0412\u0438 \u0442\u0430\u043A\u043E\u0436 \u043C\u043E\u0436\u0435\u0442\u0435 \u0443\u0432\u0456\u0439\u0442\u0438 \u0437\u0430 \u0434\u043E\u043F\u043E\u043C\u043E\u0433\u043E\u044E Open ID \u0422\u0443\u0442. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.PleaseContactAdministrationToGetRegistrationLink=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0437\u0432\u2019\u044F\u0436\u0456\u0442\u044C\u0441\u044F \u0437 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0430\u0440\u0442\u043E\u0440\u043E\u043C \u0449\u043E\u0431 \u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u043D\u0430 \u0440\u0435\u0454\u0441\u0442\u0440\u0430\u0446\u0456\u044E. -jsf.ForgotYourPassword=\u0417\u0430\u0431\u0443\u043B\u0438 \u043F\u0430\u0440\u043E\u043B\u044C? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.ResetPassword=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C -jsf.SubmitRequest=\u0412\u0456\u0434\u043F\u0440\u0430\u0432\u0438\u0442\u0438 \u0437\u0430\u044F\u0432\u043A\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.ResetYourPassword=\u0417\u043C\u0456\u043D\u0456\u0442\u044C \u0432\u0430\u0448 \u043F\u0430\u0440\u043E\u043B\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.NewPassword=\u041D\u043E\u0432\u0438\u0439 \u043F\u0430\u0440\u043E\u043B\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.OldPassword=\u0421\u0442\u0430\u0440\u0438\u0439 \u043F\u0430\u0440\u043E\u043B\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ChangePassword=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.RememberMe=\u0417\u0430\u043F\u0430\u043C\u2019\u044F\u0442\u0430\u0442\u0438 \u043C\u0435\u043D\u0435 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.login.openid.SelectProvider=\u042F\u043A \u0432\u0438 \u0445\u043E\u0447\u0435\u0442\u0435 \u0443\u0432\u0456\u0439\u0442\u0438? -# translation auto-copied from project Zanata server, version master, document zanata-war/src/main/resources/messages, author Maks -jsf.login.openid.fedora=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 Fedora -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.login.openid.myopenid=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 MyOpenID -jsf.login.openid.yahoo=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 Yahoo -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.login.openid=Open ID -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.login.internal=\u0406\u043C\u2019\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.UsernameNotAvailable=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 "\#{userAction.username}" \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\u0439 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.FedoraUsername=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 Fedora -jsf.ActivateAccount=\u0417\u0430\u0434\u0456\u044F\u0442\u0438 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ValidateEmail=\u041F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0430 Email -jsf.InactiveAccount=\u041D\u0435\u0430\u043A\u0442\u0438\u0432\u043D\u0438\u0439 \u043E\u0431\u043B. \u0437\u0430\u043F\u0438\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.inactiveaccount.PleaseSelectOne=\u0412\u0430\u0448 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 \u0449\u0435 \u043D\u0435 \u0430\u043A\u0442\u0438\u0432\u043E\u0432\u0430\u043D\u043E. \u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0432\u0438\u043A\u043E\u043D\u0430\u0439\u0442\u0435 \u043E\u0434\u0438\u043D \u0437 \u043D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0445 \u043A\u0440\u043E\u043A\u0456\u0432\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.ResendActivationEmail=\u0429\u0435 \u0440\u0430\u0437 \u043D\u0430\u0434\u0456\u0441\u043B\u0430\u0442\u0438 \u043B\u0438\u0441\u0442 \u0456\u0437 \u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0456\u0454\u044E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.or=\u0410\u0411\u041E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.inactiveaccount.UpdateAndResend=\u041E\u043D\u043E\u0432\u0438\u0442\u0438 e-mail \u0430\u0434\u0440\u0435\u0441\u0443 \u0442\u0430 \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u0438\u0442\u0438 \u043B\u0438\u0441\u0442 \u0437 \u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0456\u0454\u044E \u0449\u0435 \u0440\u0430\u0437\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.UpdateEmail=\u041E\u043D\u043E\u0432\u0438\u0442\u0438 \u0430\u0434\u0440\u0435\u0441\u0443 \u0435\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0457 \u043F\u043E\u0448\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.InvalidActivationKey=\u041D\u0435\u0432\u0456\u0440\u043D\u0438\u0439 \u043A\u043E\u0434 \u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0456\u0457 -jsf.ActivationLinkExpired=\u0422\u0435\u0440\u043C\u0456\u043D \u0434\u0456\u0457 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u043C\u0438\u043D\u0443\u0432. \u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0443\u0432\u0456\u0439\u0434\u0456\u0442\u044C \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u0442\u0430 \u043D\u0430\u0442\u0438\u0441\u043D\u0456\u0442\u044C "\#{messages['jsf.ResendActivationEmail']}". -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Error=\u041F\u043E\u043C\u0438\u043B\u043A\u0430 -jsf.ErrorTitle=\u041F\u043E\u0442\u043E\u0447\u043D\u0456 \u043F\u043E\u043C\u0438\u043B\u043A\u0438\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Xander -jsf.NoErrors=\u041F\u043E\u043C\u0438\u043B\u043E\u043A \u043D\u0435\u043C\u0430\u0454 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.EditProfile=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u043F\u0440\u043E\u0444\u0456\u043B\u044C -jsf.ManageIdentities=\u041A\u0435\u0440\u0443\u0432\u0430\u043D\u043D\u044F \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u043C\u0438 \u0437\u0430\u043F\u0438\u0441\u0430\u043C\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.identities.MergeAccount=\u041E\u0431\u2019\u0454\u0434\u043D\u0430\u0442\u0438 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0456 \u0437\u0430\u043F\u0438\u0441\u0438 -jsf.identities.MergeAccount.tootip=\u0421\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u0439\u0442\u0435\u0441\u044C \u0446\u0438\u043C, \u0449\u043E\u0431 \u043E\u0431\u2019\u0454\u0434\u043D\u0430\u0442\u0438 \u0434\u0432\u0430 \u043E\u0431\u043B. \u0437\u0430\u043F\u0438\u0441\u0438 Zanata \u0432 \u043E\u0434\u0438\u043D. -jsf.ApiKey=\u041A\u043B\u044E\u0447 API -jsf.YourCurrentApiKeyIs=\u0412\u0430\u0448 \u043A\u043B\u044E\u0447 API -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.NotGenerated=(Not generated) -jsf.apikey.ConfirmGenerate=\u0412\u0438 \u0434\u0456\u0439\u0441\u043D\u043E \u0445\u043E\u0447\u0435\u0442\u0435 \u0437\u0433\u0435\u043D\u0435\u0440\u0443\u0432\u0430\u0442\u0438 \u0432\u043B\u0430\u0441\u043D\u0438\u0439 \u043A\u043B\u044E\u0447 API? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ConfigurationForZanataini=\u041D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F [zanata.ini] -jsf.MaintainedProjects=\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u043E\u0432\u0430\u043D\u0456 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 -jsf.LanguageTeams=\u041A\u043E\u043C\u0430\u043D\u0434\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 -jsf.MaintainedGroups=\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u043E\u0432\u0430\u043D\u0456 \u0433\u0440\u0443\u043F\u0438 -jsf.FirstExternalLoginMessage=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u0442\u0435 \u0432\u0432\u0435\u0434\u0435\u043D\u0443 \u0430\u0434\u0440\u0435\u0441\u0443 \u0435\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0457 \u043F\u043E\u0448\u0442\u0438 \u043D\u0438\u0436\u0447\u0435 \u0442\u0430 \u043D\u0430\u0442\u0438\u0441\u043D\u0456\u0442\u044C \u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438 \u0449\u043E\u0431 \u043F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0438 \u0457\u0457. -jsf.AccountDetails=\u0414\u0435\u0442\u0430\u043B\u0456 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443 -jsf.identities.Title=\u041E\u0431\u043B\u0456\u043A\u043E\u0432\u0456 \u0437\u0430\u043F\u0438\u0441\u0438 -jsf.identities.ConfirmIdentityRemoval=\u0412\u0438 \u0434\u0456\u0439\u0441\u043D\u043E \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0446\u0435\u0439 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441? \u0412\u0438 \u043D\u0435 \u0437\u043C\u043E\u0436\u0435\u0442\u0435 \u0431\u0456\u043B\u044C\u0448\u0435 \u0412\u0445\u043E\u0434\u0438\u0442\u0438 \u0437 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F\u043C \u0446\u044C\u043E\u0433\u043E \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.identities.Type=\u0422\u0438\u043F -jsf.identities.User=\u041E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 -jsf.identities.AddIdentity=\u0414\u043E\u0434\u0430\u0442\u0438 \u043D\u043E\u0432\u0438\u0439 \u041E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 -jsf.identities.Verify=\u041F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0436\u0435\u043D\u043D\u044F \u041E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.profile.MergeAccount=\u041E\u0431\u2019\u0454\u0434\u043D\u0430\u0442\u0438 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0456 \u0437\u0430\u043F\u0438\u0441\u0438 -jsf.profile.MergeAccount.info=\u0423\u0432\u0456\u0439\u0434\u0456\u0442\u044C \u043F\u0456\u0434 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u043C \u0437\u0430\u043F\u0438\u0441\u043E\u043C \u044F\u043A\u0438\u0439 \u0445\u043E\u0447\u0435\u0442\u0435 \u043E\u0431\u2019\u0454\u0434\u043D\u0430\u0442\u0438. \u0412\u0438 \u043C\u043E\u0436\u0435\u0442\u0435 \u0441\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u0439\u0442\u0435\u0441\u044C \u043E\u0434\u043D\u0438\u043C \u0456\u0437 \u043D\u0438\u0449\u0435\u0432\u043A\u0430\u0437\u0430\u043D\u0438\u0445 \u043C\u0435\u0442\u043E\u0434\u0456\u0432 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0456\u0457. \u041F\u0456\u0441\u043B\u044F \u0446\u044C\u043E\u0433\u043E \u0443 \u0412\u0430\u0441 \u0431\u0443\u0434\u0435 \u0437\u0430\u043F\u0438\u0442\u0430\u043D\u043E \u043F\u043E\u0434\u0430\u043B\u044C\u0448\u0435 \u043F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0436\u0435\u043D\u043D\u044F. -jsf.profile.MergeAccount.confirm=\u0412\u0438\u043A\u043E\u043D\u0430\u0442\u0438 -jsf.profile.MergeAccount.confirmationMessage=\u0412\u0438 \u0437\u0431\u0438\u0440\u0430\u0454\u0442\u0435\u0441\u044C \u0432\u0438\u043A\u043E\u043D\u0430\u0442\u0438 \u0437\u043B\u0438\u0442\u0442\u044F \u043D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0445 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0445 \u0437\u0430\u043F\u0438\u0441\u0456\u0432\:

\u0406\u043C\u2019\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\: \#{accountMergeAction.obsoleteAccount.username}
\u0406\u043C\u2019\u044F\: \#{accountMergeAction.obsoleteAccount.person.name}
Email\: \#{accountMergeAction.obsoleteAccount.person.email}

\u0426\u0435 \u0437\u043C\u0456\u043D\u0430 \u043F\u043E\u0441\u0442\u0456\u0439\u043D\u0430 \u0456 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u043F\u043E\u0432\u0435\u0440\u043D\u0435\u043D\u0430 \u043D\u0430\u0437\u0430\u0434.

\u0417\u0433\u0430\u0434\u0430\u043D\u0438\u0439 \u0432\u0438\u0449\u0435 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 \u0431\u0443\u0434\u0435 \u0432\u0438\u043C\u043A\u043D\u0443\u043D\u043E \u0456 \u0432\u0456\u0434\u043C\u0456\u043D\u0435\u043D\u043E \u0432\u0441\u0456 \u0439\u043E\u0433\u043E \u043F\u0440\u0430\u0432\u0430. \u041F\u043E\u0442\u043E\u0447\u043D\u0438\u0439 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 \u043D\u0430\u0441\u043B\u0456\u0434\u0443\u0454 \u0446\u0456 \u043F\u0440\u0430\u0432\u0430.

\u0412\u0438 \u0441\u043F\u0440\u0430\u0434\u0432\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0446\u0435 \u0437\u0440\u043E\u0431\u0438\u0442\u0438? -jsf.ServerConfiguration=\u0421\u0435\u0440\u0432\u0435\u0440\u043D\u0456 \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageUsers=\u0423\u043F\u0440\u0430\u0432\u043B\u0456\u043D\u043D\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u043C\u0438 -jsf.ManageRoles=\u041A\u0435\u0440\u0443\u0432\u0430\u0442\u0438 \u0440\u0456\u0432\u043D\u044F\u043C\u0438 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0456\u0432 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageLanguage=\u0423\u043F\u0440\u0430\u0432\u043B\u0456\u043D\u043D\u044F\u043C\u0438 \u043C\u043E\u0432\u0430\u043C\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageSearch=\u0423\u043F\u0440\u0430\u0432\u043B\u0456\u043D\u043D\u044F \u043F\u043E\u0448\u0443\u043A\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.OverallStatistics=\u0417\u0430\u0433\u0430\u043B\u044C\u043D\u0430 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430 -jsf.RoleAssignmentRules=\u041F\u0440\u0430\u0432\u0438\u043B\u0430 \u041F\u0440\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0420\u0456\u0432\u043D\u0456\u0432 -jsf.ServerMonitoring=\u041A\u043E\u043D\u0442\u0440\u043E\u043B\u044C \u0441\u0435\u0440\u0432\u0435\u0440\u0430 -jsf.ProcessManager=\u041C\u0435\u043D\u0435\u0434\u0436\u0435\u0440 \u043F\u0440\u043E\u0446\u0435\u0441\u0456\u0432 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ServerUrl=URL \u0421\u0435\u0440\u0432\u0435\u0440\u0430 -jsf.UrlToolTip=\u041E\u0441\u043D\u043E\u0432\u043D\u0438\u0439 URL \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0432\u043A\u043B\u044E\u0447\u043D\u043E \u0437 \u0448\u043B\u044F\u0445\u043E\u043C \u0434\u043E \u0437\u0430\u0441\u0442\u043E\u0441\u0443\u043D\u043A\u0443 (\u0431\u0435\u0437 \u0441\u043B\u0435\u0448\u0430 \u0432 \u043A\u0456\u043D\u0446\u0456) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.UrlExample=\u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434 http\://example.com/zanata \u0430\u0431\u043E http\://zanata.example.com -jsf.RegisterUrl=\u0417\u0430\u0440\u0435\u0454\u0441\u0442\u0440\u0443\u0432\u0430\u0442\u0438 URL -jsf.RegisterUrlToolTip=URL \u0440\u0435\u0454\u0441\u0442\u0440\u0430\u0446\u0456\u0457 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 -jsf.RegisterUrlExample=\u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434, /zanata/account/register \u0430\u0431\u043E http\://example.com/register -jsf.EmailDomainName=\u041D\u0430\u0437\u0432\u0430 e-mail \u0434\u043E\u043C\u0435\u043D\u0443 -jsf.EmailDomainNameToolTip=\u041D\u0430\u0437\u0432\u0430 e-mail \u0434\u043E\u043C\u0435\u043D\u0443 \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0443 \u0444\u043E\u0440\u043C\u0430\u0442\u0456 example.com. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.EmailDomainNameExample=\u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434, redhat.com -jsf.config.AdminEmail=\u041A\u043E\u043D\u0442\u0430\u043A\u0442\u043D\u0430 \u0430\u0434\u0440\u0435\u0441\u0430 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 -jsf.config.AdminEmail.tooltip=E-mail \u043D\u0430 \u044F\u043A\u0438\u0439 \u0431\u0443\u0434\u0443\u0442\u044C \u0432\u0456\u0434\u0441\u0438\u043B\u0430\u0442\u0438\u0441\u044C \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F \u0437 \u0444\u043E\u0440\u043C\u0438 '\u0417\u0432\u2019\u044F\u0437\u0430\u0442\u0438\u0441\u044C \u0437 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C'. -jsf.config.AdminEmail.DoesNotChangeUserEmail=\u0426\u0435 \u043F\u043E\u043B\u0435 \u043D\u0435 \u0437\u043C\u0456\u043D\u044E\u0454 \u043E\u0441\u043E\u0431\u0438\u0441\u0442\u0443 \u0430\u0434\u0440\u0435\u0441\u0443 e-mail \u0434\u043B\u044F \u0436\u043E\u0434\u043D\u043E\u0433\u043E \u0437 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0456\u0432. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.EmailListToolTip=Email \u0430\u0434\u0440\u0435\u0441\u0438 \u043C\u0430\u044E\u0442\u044C \u0431\u0443\u0442\u0438 \u0440\u043E\u0437\u0434\u0456\u043B\u0435\u043D\u0456 \u043E\u0434\u043D\u0456\u0454\u044E \u043A\u043E\u043C\u043E\u044E (,) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.config.FromEmailAddr=\u0417 e-mail \u0430\u0434\u0440\u0435\u0441\u0438 -jsf.config.FromEmailAddr.tooltip=\u0426\u0435 \u0431\u0443\u0434\u0435 \u0432\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043E \u0432 \u043F\u043E\u043B\u0435 '\u0412\u0456\u0434' \u0434\u043B\u044F \u0432\u0441\u0456\u0445 \u043B\u0438\u0441\u0442\u0456\u0432, \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0445 \u043F\u043E\u0442\u043E\u0447\u043D\u0438\u043C \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C zanata. -jsf.config.EnableLogEmails=\u0423\u0432\u0456\u043C\u043A\u043D\u0443\u0442\u0438 \u043B\u0438\u0441\u0442\u0438 \u0437 \u0436\u0443\u0440\u043D\u0430\u043B\u0430\u043C\u0438 -jsf.config.EnableLogEmails.tooltip=\u0423\u0432\u0456\u043C\u043A\u043D\u0443\u0442\u0438 \u0430\u0431\u043E \u0432\u0438\u043C\u043A\u043D\u0443\u0442\u0438 \u0432\u0456\u0434\u043F\u0440\u0430\u043B\u0435\u043D\u044F Zanata \u0434\u0456\u0430\u0433\u043D\u043E\u0441\u0442\u0438\u0447\u043D\u0438\u0445 \u0436\u0443\u0440\u043D\u0430\u043B\u0456\u0432 \u043D\u0430 \u0435-mail. -jsf.config.LogDestEmail=\u041B\u043E\u0433\u0443\u0432\u0430\u0442\u0438 \u0430\u0434\u0440\u0435\u0441\u0438 \u043E\u0442\u0440\u0438\u043C\u0443\u0432\u0430\u0447\u0456\u0432 e-mail. -jsf.config.LogDestEmail.tooltip=\u041A\u043E\u043B\u0438 \u0431\u0443\u0434\u0435 \u0432\u0438\u043A\u043E\u043D\u0443\u0432\u0430\u0442\u0438\u0441\u044C \u043B\u043E\u0433\u0443\u0432\u0430\u043D\u043D\u044F \u043D\u0430 \u0446\u0456 \u043F\u043E\u0448\u0442\u043E\u0432\u0456 \u0430\u0434\u0440\u0435\u0441\u0438 \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u0438\u0442\u044C\u0441\u044F \u043B\u0438\u0441\u0442. -jsf.config.LogEmailLevel=\u0420\u0456\u0432\u0435\u043D\u044C \u0436\u0443\u0440\u043D\u0430\u043B\u0456\u0432 \u0449\u043E \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u043B\u044F\u0442\u0438\u043C\u0443\u0442\u044C\u0441\u044F -jsf.config.LogEmailLevel.tooltip=\u0420\u0456\u0432\u043D\u0456 \u0436\u0443\u0440\u043D\u0430\u043B\u0456\u0432 \u043D\u0430\u0441\u0442\u0443\u043F\u043D\u0456\: \u041F\u043E\u043C\u0438\u043B\u043A\u0438 \u2013 \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0442\u044C\u0441\u044F \u0442\u0456\u043B\u044C\u043A\u0438 \u043B\u0438\u0441\u0442\u0438 \u0437 \u043F\u043E\u043C\u0438\u043B\u043A\u0430\u043C\u0438 , \u041F\u043E\u043F\u0435\u0440\u0435\u0434\u0436\u0435\u043D\u043D\u044F \u2013 \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0442\u044C\u0441\u044F \u043B\u0438\u0441\u0442\u0438 \u0437 \u043F\u043E\u043F\u0435\u0440\u0435\u0434\u0436\u0435\u043D\u043D\u044F\u043C\u0438 \u0442\u0430 \u043F\u043E\u043C\u0438\u043B\u043A\u0430\u043C\u0438. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Warning=\u0423\u0432\u0430\u0433\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.config.PiwikUrl=Piwik URL -jsf.config.Piwiktooltip=URL \u043D\u0430 \u0430\u043D\u0430\u043B\u0456\u0442\u0438\u0447\u043D\u0443 \u0443\u0442\u0438\u043B\u0456\u0442\u0443 Piwik. \u0442\u043E \u0454 http\://localhost/piwik -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.config.PiwikIdSite=Piwik ID -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.config.PiwikIdSitetooltip=ID \u0441\u0430\u0439\u0442\u0443 \u0432 Piwik -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CreateNewUser=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u043E\u0433\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 -jsf.MemberOf=\u0404 \u0447\u043B\u0435\u043D\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.Enabled=\u0423\u0432\u0456\u043C\u043A\u043D\u0435\u043D\u043E -jsf.AreYouSureYouWishToDeleteThisUserThisActionCannotBeUndone=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0446\u044C\u043E\u0433\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430? \u0426\u044F \u0434\u0456\u044F \u043D\u0435\u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u0432\u0456\u0434\u043C\u0456\u043D\u0435\u043D\u0430. -jsf.UserManager.delete.constraintViolation.error=\u0426\u044C\u043E\u0433\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 \u043D\u0435 \u043C\u043E\u0436\u043D\u0430 \u0432\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0437 \u0441\u0438\u0441\u0442\u0435\u043C\u0438. \u0410\u043B\u0435 \u0432\u0437\u0430\u043C\u0456\u043D \u0432\u0438 \u043C\u043E\u0436\u0435\u0442\u0435 \u0439\u043E\u0433\u043E \u0432\u0438\u043C\u043A\u043D\u0443\u0442\u0438. -jsf.AccountEnabled=\u041E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 \u0443\u0432\u0456\u043C\u043A\u043D\u0435\u043D\u043E -jsf.CreateRole=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0440\u0456\u0432\u0435\u043D\u044C -jsf.AreYouSureYouWishToDeleteThisRoleThisActionCannotBeUndone=\u0412\u0438 \u0434\u0456\u0439\u0441\u043D\u043E \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0446\u044C\u043E\u0433\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430? \u0426\u044F \u0434\u0456\u044F \u043D\u0435\u0432\u0456\u0434\u0432\u043E\u0440\u043E\u0442\u043D\u0430. -jsf.Role=\u0420\u0456\u0432\u0435\u043D\u044C -jsf.RoleDetails=\u0414\u0435\u0442\u0430\u043B\u0456 \u0440\u0456\u0432\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.EnabledByDefault=\u0423\u0432\u0456\u043C\u043A\u043D\u0435\u043D\u043E \u0437\u0430 \u0437\u0430\u043C\u043E\u0432\u0447\u0435\u043D\u043D\u044F\u043C -jsf.AreYouSureYouWishToDeleteThisLanguageThisActionCannotBeUndone=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u043B\u0443\u0447\u0438\u0442\u0438 \u0446\u044E \u043C\u043E\u0432\u0443? \u0426\u044F \u0434\u0456\u044F \u043D\u0435 \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u0432\u0456\u0434\u043C\u0456\u043D\u0435\u043D\u0430 \u0432 \u043C\u0430\u0439\u0431\u0443\u0442\u043D\u044C\u043E\u043C\u0443. -jsf.AreYouSureYouWishToEnableThisLanguage=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0443\u0432\u0456\u043C\u043A\u043D\u0443\u0442\u0438 \u0446\u044E \u043C\u043E\u0432\u0443? -jsf.AreYouSureYouWishToDisableThisLanguage=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u043C\u043A\u043D\u0443\u0442\u0438 \u0446\u044E \u043C\u043E\u0432\u0443? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.language.manager.DisableByDefaultConfirmation=\u0412\u0438 \u0434\u0456\u0439\u0441\u043D\u043E \u0431\u0430\u0436\u0430\u0454\u0442\u0435 \u0449\u043E\u0431 \u0434\u0430\u043D\u0430 \u043C\u043E\u0432\u0430 \u0431\u0443\u043B\u0430 \u0432\u0438\u043C\u043A\u043D\u0435\u043D\u0430 \u0437\u0430 \u0437\u0430\u043C\u043E\u0432\u0447\u0435\u043D\u043D\u044F\u043C? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.language.manager.EnableByDefaultConfirmation=\u0412\u0438 \u0434\u0456\u0439\u0441\u043D\u043E \u0431\u0430\u0436\u0430\u0454\u0442\u0435 \u0449\u043E\u0431 \u0434\u0430\u043D\u0430 \u043C\u043E\u0432\u0430 \u0431\u0443\u043B\u0430 \u0443\u0432\u0456\u043C\u043A\u043D\u0435\u043D\u0430 \u0437\u0430 \u0437\u0430\u043C\u043E\u0432\u0447\u0435\u043D\u043D\u044F\u043C? -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.TeamMembers=\u0423\u0447\u0430\u0441\u043D\u0438\u043A\u0438 \u043A\u043E\u043C\u0430\u043D\u0434\u0438 -jsf.language.validation.ReplaceUnderscores=\u0417\u0430\u043C\u0456\u043D\u0438\u0442\u0438 \u0457\u0445. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.language.validation.Underscores=\u0417\u043D\u0430\u043A\u0438 \u043F\u0456\u0434\u043A\u0440\u0435\u0441\u043B\u0435\u043D\u043D\u044F (_) \u043C\u0430\u044E\u0442\u044C \u0431\u0443\u0442\u0438 \u0437\u0430\u043C\u0456\u043D\u0435\u043D\u0456 \u043D\u0430 \u0442\u0438\u0440\u0435 (-). -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.CountryCode=\u041A\u043E\u0434 \u043A\u0440\u0430\u0457\u043D\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.LanguageCode=\u041A\u043E\u0434 \u043C\u043E\u0432\u0438 -jsf.Variant=\u0412\u0430\u0440\u0456\u0430\u043D\u0442 -jsf.language.validation.Invalid=\u041D\u0435\u0432\u0456\u0440\u043D\u0430 \u043D\u0430\u0437\u0432\u0430 \u043C\u043E\u0432\u0438 -jsf.language.validation.Existing=\u041C\u043E\u0432\u0430 \u0432\u0436\u0435 \u043F\u0440\u0438\u0441\u0443\u0442\u043D\u044F -jsf.language.validation.SimilarLocaleFound=\u0417\u043D\u0430\u0439\u0434\u0435\u043D\u043E \u0441\u0445\u043E\u0436\u0456 \u043C\u043E\u0432\u0438\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.manageSearch.AllActions=(\u0432\u0441\u0456 \u0434\u0456\u0457) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.manageSearch.Table=\u0422\u0430\u0431\u043B\u0438\u0446\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.manageSearch.AllTables=(\u0432\u0441\u0456 \u0442\u0430\u0431\u043B\u0438\u0446\u0456) -jsf.manageSearch.purge=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0456\u043D\u0434\u0435\u043A\u0441 -jsf.manageSearch.purge.ObsoletesOccupyDiskSpace=\u0417\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0456 \u043F\u0440\u043E\u0435\u043A\u0442\u0438 \u043F\u0440\u043E\u0434\u043E\u0432\u0436\u0443\u044E\u0442\u044C \u0437\u0430\u0439\u043C\u0430\u0442\u0438 \u0434\u0438\u0441\u043A\u043E\u0432\u0438\u0439 \u043F\u0440\u043E\u0441\u0442\u0456\u0440 \u043F\u0440\u043E\u0442\u0435 \u0432\u043E\u043D\u0438 \u043D\u0435 \u0437\u043D\u0430\u0445\u043E\u0434\u044F\u0442\u044C\u0441\u044F \u0437\u0430 \u0434\u043E\u043F\u043E\u043C\u043E\u0433\u043E\u044E \u043F\u043E\u0448\u0443\u043A\u0443. -jsf.manageSearch.purge.RemoveByRunningOptimize=\u0417\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0456 \u0434\u0430\u043D\u0456 \u043C\u043E\u0436\u043D\u0430 \u0446\u0456\u043B\u043A\u043E\u043C \u0432\u0438\u0434\u0430\u043B\u0438\u0442\u0438, \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0432\u0448\u0438 \u041E\u043F\u0442\u0438\u043C\u0456\u0437\u0430\u0446\u0456\u044E \u0431\u0443\u0434\u044C-\u043A\u043E\u043B\u0438 \u043F\u0456\u0441\u043B\u044F \u041E\u0447\u0438\u0441\u0442\u043A\u0438. -jsf.manageSearch.reindex=\u041E\u043D\u043E\u0432\u0438\u0442\u0438 \u0406\u043D\u0434\u0435\u043A\u0441 -jsf.manageSearch.reindex.Description=\u041F\u0440\u043E\u0456\u043D\u0434\u0435\u043A\u0441\u0443\u0432\u0430\u0442\u0438 \u0432\u0441\u0456 \u0440\u044F\u0434\u043A\u0438 \u0434\u0430\u043D\u043E\u0457 \u0442\u0430\u0431\u043B\u0438\u0446\u0456 -jsf.manageSearch.reindex.OnlyWhenOutOfDate=\u0420\u044F\u0434\u043A\u0438 \u0456\u043D\u0434\u0435\u043A\u0441\u0443\u044E\u0442\u044C\u0441\u044F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E \u0437\u0456 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F\u043C \u0434\u0430\u043D\u0438\u0445, \u0442\u043E\u043C\u0443 \u0446\u044F \u0434\u0456\u044F \u043F\u043E\u0442\u0440\u0456\u0431\u043D\u0430 \u043B\u0438\u0448\u0435 \u043A\u043E\u043B\u0438 \u0456\u043D\u0434\u0435\u043A\u0441 \u0441\u0442\u0430\u0454 \u0437\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0438\u043C (\u043D.\u043F. \u043A\u043E\u043B\u0438 \u0431\u0430\u0437\u0430 \u0434\u0430\u043D\u0438\u0445 \u0432\u0456\u0434\u043D\u043E\u0432\u043B\u044E\u0432\u0430\u043B\u0430\u0441\u044F \u0437 \u0431\u0435\u043A\u0430\u043F\u0443 \u043F\u0456\u0441\u043B\u044F \u043D\u0435\u0432\u0434\u0430\u043B\u043E\u0433\u043E \u043E\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u044F \u0456\u043D\u0434\u0435\u043A\u0441\u0443, \u044F\u043A\u0449\u043E \u0456\u043D\u0434\u0435\u043A\u0441 \u0431\u0443\u043B\u043E \u0432\u0442\u0440\u0430\u0447\u0435\u043D\u043E. -jsf.manageSearch.reindex.AllRowsWillBeReindexed=\u0412\u0441\u0456 \u0440\u044F\u0434\u043A\u0438 \u0442\u0430\u0431\u043B\u0438\u0446\u0456 \u0431\u0443\u0434\u0435 \u043F\u0440\u043E\u0456\u043D\u0434\u0435\u043A\u0441\u043E\u0432\u0430\u043D\u043E, \u043D\u0435\u0437\u0430\u043B\u0435\u0436\u043D\u043E \u0432\u0456\u0434 \u0457\u0445 \u043D\u0430\u044F\u0432\u043D\u043E\u0441\u0442\u0456/\u0432\u0456\u0434\u0441\u0443\u0442\u043D\u043E\u0441\u0442\u0456 \u0432 \u0456\u043D\u0434\u0435\u043A\u0441\u0456. -jsf.manageSearch.reindex.IndexedRowsWillBeUpdated=\u041F\u0440\u043E\u0456\u043D\u0434\u0435\u043A\u0441\u043E\u0432\u0430\u043D\u0456 \u0440\u044F\u0434\u043A\u0438 \u0431\u0443\u0434\u0443\u0442\u044C \u043E\u043D\u043E\u0432\u043B\u0435\u043D\u0456. \u0417\u0430\u0437\u0432\u0438\u0447\u0430\u0439 \u0446\u0435 \u043D\u0435 \u0432\u043F\u043B\u0438\u0432\u0430\u0454 \u043D\u0430 \u0457\u0445 \u0432\u043C\u0456\u0441\u0442. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.manageSearch.reindex.TimeAndMemoryWarning=\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u0436\u0435\u043D\u043D\u044F\: \u0434\u043B\u044F \u0432\u0435\u043B\u0438\u043A\u0438\u0445 \u0442\u0430\u0431\u043B\u0438\u0446\u044C \u0446\u044F \u043E\u043F\u0435\u0440\u0446\u0456\u044F \u043C\u043E\u0436\u0435 \u0442\u0440\u0438\u0432\u0430\u0442\u0438 \u0434\u0435\u043A\u0456\u043B\u044C\u043A\u0430 \u0433\u043E\u0434\u0438\u043D \u0456 \u043C\u043E\u0436\u0435 \u0437\u0443\u043C\u043E\u0432\u0438\u0442\u0438 \u0437\u043D\u0430\u0447\u043D\u043E \u0431\u0456\u043B\u044C\u0448\u0435 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F \u043F\u0430\u043C\u2019\u044F\u0442\u0456. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.manageSearch.reindex.RunDuringOffPeak=\u0420\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0454\u0442\u044C\u0441\u044F \u0432\u0438\u043A\u043E\u043D\u0443\u0432\u0430\u0442\u0438 \u0446\u044E \u043E\u043F\u0435\u0440\u0430\u0446\u0456\u044E \u043D\u0435 \u0432 \u0433\u043E\u0434\u0438\u043D\u0438-\u043F\u0456\u043A, \u043A\u043E\u043B\u0438 \u0441\u0435\u0440\u0435\u0434\u043D\u0454 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F \u043F\u0430\u043C\u2019\u044F\u0442\u0456 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C \u043C\u0456\u043D\u0456\u043C\u0430\u043B\u044C\u043D\u0435. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.manageSearch.optimize=\u041E\u043F\u0442\u0438\u043C\u0456\u0437\u0443\u0432\u0430\u0442\u0438 -jsf.manageSearch.optimize.Description=\u0423\u043F\u043E\u0440\u044F\u0434\u043A\u0443\u0432\u0430\u0442\u0438 \u0434\u0430\u043D\u0456 \u0456\u043D\u0434\u0435\u043A\u0441\u0443 \u0434\u043B\u044F \u043F\u0440\u0438\u0448\u0432\u0438\u0434\u0448\u0435\u043D\u043D\u044F \u043F\u043E\u0448\u0443\u043A\u0443 -jsf.manageSearch.optimize.RemovesObsoleteEntries=\u0422\u0430\u043A\u043E\u0436 \u0432\u0438\u0434\u0430\u043B\u044F\u0454 \u0437\u0430\u0441\u0442\u0430\u0440\u0456\u043B\u0456 \u0434\u0430\u043D\u0456 \u0437 \u0456\u043D\u0434\u0435\u043A\u0441\u0443 -jsf.manageSearch.optimize.WillNotInfluenceIndexTime=\u041D\u0435 \u0432\u043F\u043B\u0438\u0432\u0430\u0442\u0438\u043C\u0435 \u043D\u0430 \u0447\u0430\u0441 \u0456\u043D\u0434\u0435\u043A\u0441\u0443\u0432\u0430\u043D\u043D\u044F. -jsf.manageSearch.optimize.TempFileWarning=\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u0436\u0435\u043D\u043D\u044F\: \u0446\u044F \u043E\u043F\u0435\u0440\u0430\u0446\u0456\u044F \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454 \u0442\u0438\u043C\u0447\u0430\u0441\u043E\u0432\u0438\u0439 \u0444\u0430\u0439\u043B, \u0449\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0443\u0454 \u0432\u0456\u043B\u044C\u043D\u043E\u0433\u043E \u043C\u0456\u0441\u0446\u044F \u043D\u0430 \u0434\u0438\u0441\u043A\u0443, \u043F\u0440\u0438\u0431\u043B\u0438\u0437\u043D\u043E \u0441\u0442\u0456\u043B\u044C\u043A\u0438, \u044F\u043A \u043F\u043E\u0442\u043E\u0447\u043D\u0438\u0439 \u0440\u043E\u0437\u043C\u0456\u0440 \u0456\u043D\u0434\u0435\u043A\u0441\u0443. -jsf.ManageSearch.SelectNone=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0432\u0438\u0434\u0456\u043B\u0435\u043D\u0435 -jsf.ManageSearch.PerformSelectedActions=\u0412\u0438\u043A\u043E\u043D\u0430\u0442\u0438 \u0432\u0438\u0431\u0440\u0430\u043D\u0456 \u0434\u0456\u0457 -jsf.ManageSearch.CurrentProgress=\u041F\u0440\u043E\u0433\u0440\u0435\u0441 -jsf.ManageSearch.NoOperationsRunning=\u0416\u043E\u0434\u043D\u043E\u0457 \u043E\u043F\u0435\u0440\u0430\u0446\u0456\u0457 \u043D\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageSearch.Completed=\u0423\u0441\u043F\u0456\u0448\u043D\u043E \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E (\u0442\u0440\u0438\u0432\u0430\u043B\u0456\u0441\u0442\u044C \#{reindexAction.elapsedTime}) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageSearch.Aborted=\u0412\u0456\u0434\u043C\u0456\u043D\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0435\u043C (\u0442\u0440\u0438\u0432\u0430\u043B\u0456\u0441\u0442\u044C \#{reindexAction.elapsedTime}) -jsf.manageSearch.PleaseReindex=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u043F\u0440\u043E\u0432\u0435\u0434\u0456\u0442\u044C \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u0443 \u0456\u043D\u0434\u0435\u043A\u0441\u0430\u0446\u0456\u044E \u0434\u043B\u044F \u0430\u043A\u0442\u0443\u0430\u043B\u0456\u0437\u0430\u0446\u0456\u0457 \u043F\u043E\u0448\u0443\u043A\u043E\u0432\u043E\u0433\u043E \u0456\u043D\u0434\u0435\u043A\u0441\u0443 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.manageSearch.ProgressMessage=\#{reindexAction.reindexProgress} \u0437 \#{reindexAction.reindexCount} \u043E\u043F\u0435\u0440\u0430\u0446\u0456\u0439 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E -jsf.manageSearch.CurrentTable=\u041E\u0431\u0440\u043E\u0431\u043A\u0430 \u0442\u0430\u0431\u043B\u0438\u0446\u0456\: \#{reindexAction.currentClass} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageSearch.ElapsedTime=\u0412\u0438\u043A\u043E\u043D\u0443\u0454\u0442\u044C\u0441\u044F\: \#{reindexAction.elapsedTime} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageSearch.RemainingTime=\u0417\u0430\u043B\u0438\u0448\u0438\u043B\u043E\u0441\u044C (\u043F\u0440\u0438\u0431\u043B\u0438\u0437\u043D\u043E)\: \#{reindexAction.estimatedTimeRemaining} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.ManageSearch.Abort=\u041F\u0435\u0440\u0435\u0440\u0432\u0430\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.TotalTranslators=\u0417\u0430\u0433\u0430\u043B\u043E\u043C \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.TotalProjects=\u0417\u0430\u0433\u0430\u043B\u043E\u043C \u043F\u0440\u043E\u0435\u043A\u0442\u0456\u0432 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.TotalProjectVersion=\u0412\u0435\u0440\u0441\u0456\u0457 \u043F\u0440\u043E\u0435\u043A\u0442\u0456\u0432 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.TotalDocuments=\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 -jsf.TotalTextFlowTargets=\u041F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0438 -# translation auto-copied from project Publican, version 3, document publican -jsf.Untranslated=\u041D\u0435 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0435\u043D\u043E -jsf.RejectedOrFuzzy=\u0412\u0456\u0434\u043A\u0438\u043D\u0443\u0442\u0456 \u0447\u0438 \u0421\u043F\u0456\u0440\u043D\u0456 -jsf.rolerules.CreateRule=\u041D\u043E\u0432\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u043E -jsf.rolerules.CreateRoleAssignmentRule=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u041F\u0440\u0430\u0432\u0438\u043B\u043E \u041F\u0440\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0420\u0456\u0432\u043D\u044F -jsf.rolerules.EditRoleAssignmentRule=\u0417\u043C\u0456\u043D\u0438\u0442\u0438 \u041F\u0440\u0430\u0432\u0438\u043B\u043E \u041F\u0440\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0420\u0456\u0432\u043D\u044F -jsf.rolerules.ConfirmDelete=\u0412\u0438 \u0441\u043F\u0440\u0430\u0432\u0434\u0456 \u0445\u043E\u0447\u0435\u0442\u0435 \u0432\u0438\u043B\u0443\u0447\u0438\u0442\u0438 \u0446\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u043E? -jsf.rolerules.Description=\u041F\u0440\u0430\u0432\u0438\u043B\u0430 \u041F\u0440\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0420\u0456\u0432\u043D\u044F \u0454 \u0437\u0430\u0441\u043E\u0431\u043E\u043C \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E\u0433\u043E \u043F\u0440\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0440\u0456\u0432\u043D\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430\u043C \u043F\u0456\u0434 \u0447\u0430\u0441 \u0457\u0445\u043D\u044C\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0443. \u042F\u043A\u0449\u043E \u041F\u0441\u0435\u0432\u0434\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 (\u043D.\u043F. \u043B\u043E\u0433\u0456\u043D) \u043F\u0456\u0434\u043F\u0430\u0434\u0430\u0454 \u043F\u0456\u0434 \u043F\u0435\u0432\u043D\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u0456 \u0447\u0438 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0443\u0454\u0442\u044C\u0441\u044F \u043F\u0435\u0432\u043D\u0438\u043C \u0447\u0438\u043D\u043E\u043C (\u043D.\u043F. \u0447\u0435\u0440\u0435\u0437 Open Id, \u044F\u043A\u0449\u043E \u043C\u043E\u0436\u043B\u0438\u0432\u043E), Zanata \u0437\u043C\u043E\u0436\u0435 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E \u043F\u0440\u0438\u0437\u043D\u0430\u0447\u0438\u0442\u0438 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0435\u0432\u0456 \u043F\u0435\u0432\u043D\u0438\u0439 \u0440\u0456\u0432\u0435\u043D\u044C. -jsf.rolerules.PolicyName=\u041D\u0430\u0437\u0432\u0430 \u041F\u0440\u0430\u0432\u0438\u043B\u0430 -jsf.rolerules.PolicyName.tooltip=\u0426\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0456\u0457, \u044F\u043A\u0435 \u0437\u0430\u0441\u0442\u043E\u0441\u043E\u0432\u0443\u0454\u0442\u044C\u0441\u044F \u0434\u043B\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430. \u042F\u043A\u0449\u043E \u043D\u0435 \u0432\u0456\u0434\u0437\u043D\u0430\u0447\u0435\u043D\u043E - \u0437\u0430\u0441\u0442\u043E\u0441\u043E\u0432\u0443\u0432\u0430\u0442\u0438\u043C\u0443\u0442\u044C\u0441\u044F \u0443\u0441\u0456 \u043F\u0440\u0430\u0432\u0438\u043B\u0430. -jsf.rolerules.IdentityPattern=\u0417\u0440\u0430\u0437\u043E\u043A \u041F\u0441\u0435\u0432\u0434\u043E -jsf.rolerules.IdentityPattern.tooltip=\u041F\u043E\u0441\u0442\u0456\u0439\u043D\u0438\u0439 \u0412\u0438\u0440\u0430\u0437 \u0434\u043B\u044F \u0432\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u044F, \u0447\u0438 \u043C\u043E\u0436\u0435 \u0446\u0435 \u043F\u0440\u0430\u0432\u043B\u043E \u0431\u0443\u0442\u0438 \u0437\u0430\u0441\u0442\u043E\u0441\u043E\u0432\u0430\u043D\u0435 \u0434\u043E \u0434\u0430\u043D\u043E\u0433\u043E \u041F\u0441\u0435\u0432\u0434\u043E. \u0417\u0432\u0435\u0440\u043D\u0456\u0442\u044C \u0443\u0432\u0430\u0433\u0443\: \u041F\u0441\u0435\u0432\u0434\u043E \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u0440\u0456\u0437\u043D\u0438\u043C, \u0432 \u0437\u0430\u043B\u0435\u0436\u043D\u043E\u0441\u0442\u0456 \u0432\u0456\u0434 \u043C\u0435\u0445\u0430\u043D\u0456\u0437\u043C\u0443 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0456\u0457. \u042F\u043A\u0449\u043E \u0446\u0435 \u043F\u043E\u043B\u0435 \u043F\u043E\u0440\u043E\u0436\u043D\u0454 - \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u0437\u0430\u0441\u0442\u043E\u0441\u043E\u0432\u0443\u0432\u0430\u0442\u0438\u043C\u0435\u0442\u044C\u0441\u044F \u0434\u043E \u0412\u0421\u0406\u0425 \u041F\u0441\u0435\u0432\u0434\u043E. -jsf.rolerules.RoleToAssign=\u041D\u0430\u0434\u0430\u0442\u0438 \u0420\u0456\u0432\u0435\u043D\u044C -jsf.rolerules.RoleToAssign.tooltip=\u0426\u0435\u0439 \u0440\u0456\u0432\u0435\u043D\u044C \u043D\u0430\u0434\u0430\u0432\u0430\u0442\u0438\u043C\u0435\u0442\u044C\u0441\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0435\u0432\u0456 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E \u043F\u0440\u0438 \u0432\u0438\u043A\u043E\u043D\u0430\u043D\u043D\u0456 \u043F\u0440\u0430\u0432\u0438\u043B\u0430. -jsf.processmanager.TotalRunning=\u0417\u0430\u0433\u0430\u043B\u043E\u043C \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E -jsf.processmanager.TotalFinished=\u0417\u0430\u0433\u0430\u043B\u043E\u043C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.processmanager.Type=\u0422\u0438\u043F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.processmanager.status.Stopped=\u0417\u0443\u043F\u0438\u043D\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.processmanager.status.Running=\u0412\u0438\u043A\u043E\u043D\u0443\u0454\u0442\u044C\u0441\u044F -jsf.processmanager.status.WaitingToStop=\u041E\u0447\u0456\u043A\u0443\u0432\u0430\u043D\u043D\u044F \u0437\u0443\u043F\u0438\u043D\u043A\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.processmanager.Progress=\u041F\u0440\u043E\u0433\u0440\u0435\u0441 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.processmanager.StartTime=\u0417\u0430\u043F\u0443\u0449\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.processmanager.FinishTime=\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E -jsf.processmanager.Duration=\u0422\u0440\u0438\u0432\u0430\u043B\u0456\u0441\u0442\u044C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.From=\u0412\u0456\u0434 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.ReplyAddress=\u0412\u0456\u0434\u043F\u043E\u0432\u0456\u0441\u0442\u0438 \u043D\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.ReplyAddress.description=(\u0432\u0430\u0448\u0430 e-mail \u0430\u0434\u0440\u0435\u0441\u0430) -jsf.email.Subject=\u0422\u0435\u043C\u0430 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AdditionalInfo=\u0414\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0430 \u0456\u043D\u0444\u043E\u0440\u0430\u0446\u0456\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.MessageBody=\u041F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.Send=\u0412\u0456\u0434\u043F\u0440\u0430\u0432\u0438\u0442\u0438 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F -jsf.NoProjects=\u041D\u0456\u0447\u043E\u0433\u043E \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E. -jsf.SelectProjectVersions=\u041E\u0431\u0435\u0440\u0456\u0442\u044C \u0432\u0435\u0440\u0441\u0456\u0457 \u043F\u0440\u043E\u0435\u043A\u0442\u0443 -jsf.NoProjectVersionSelected=\u0416\u043E\u0434\u043D\u043E\u0457 \u0432\u0435\u0440\u0441\u0456\u0457 \u043D\u0435 \u043E\u0431\u0440\u0430\u043D\u043E. -jsf.ClickSendMessageToProceedRequest=\u0412\u0432\u0435\u0434\u0456\u0442\u044C \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0443 \u0456\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0456\u044E \u0442\u0430 \u043D\u0430\u0442\u0438\u0441\u043D\u0456\u0442\u044C '\u0412\u0456\u0434\u043F\u0440\u0430\u0432\u0438\u0442\u0438 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F' \u0449\u043E\u0431 \u043F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.JoinGroupRequest.Subject=\u0417\u0430\u043F\u0438\u0442 \u043D\u0430 \u0432\u0441\u0442\u0443\u043F \u0434\u043E \u0433\u0440\u0443\u043F\u0438 '\#{versionGroupJoinAction.groupName}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.RequestAddProjectToGroup=\u0417\u0430\u043F\u0438\u0442 \u043D\u0430 \u0432\u0441\u0442\u0443\u043F \u0434\u043E \u0433\u0440\u0443\u043F\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.AlreadyInGroup=\u0412\u0436\u0435 \u0432 \u0433\u0440\u0443\u043F\u0456 -jsf.email.joingrouprequest.AdditionalInfoMessage=\u0414\u043B\u044F \u043F\u0440\u0438\u0448\u0432\u0438\u0434\u0448\u0435\u043D\u043D\u044F \u043E\u0431\u0440\u043E\u0431\u043A\u0438 \u0432\u0430\u0448\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0442\u0443, \u0431\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u043D\u0430\u0434\u0430\u0439\u0442\u0435 \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0443 \u0456\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0456\u044E, \u043A\u043E\u0442\u0440\u0430 \u0434\u043E\u043F\u043E\u043C\u043E\u0436\u0435 \u043A\u0435\u0440\u0456\u0432\u043D\u0438\u0446\u0442\u0432\u0443 \u0433\u0440\u0443\u043F\u0438 \u043F\u0440\u0438\u0439\u043D\u044F\u0442\u0438 \u0440\u0456\u0448\u0435\u043D\u043D\u044F -jsf.RequestToJoinLanguageTeamTitle=\u0417\u0430\u043F\u0438\u0442 \u043D\u0430 \u0432\u0441\u0442\u0443\u043F \u0434\u043E \u043A\u043E\u043C\u0430\u043D\u0434\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 '\#{sendEmail.locale.localeId.id}' -jsf.email.joinrequest.Subject=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 '\#{sendEmail.fromLoginName}' \u0431\u0430\u0436\u0430\u0454 \u043F\u0440\u0438\u0454\u0434\u043D\u0442\u0438\u0441\u044C \u0434\u043E \u043A\u043E\u043C\u0430\u043D\u0434\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 '\#{sendEmail.locale.localeId.id}' -jsf.email.ContactCoordinatorTitle=\u0417\u0432\u2019\u044F\u0437\u0430\u0442\u0438\u0441\u044C \u0437 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u043E\u043C '\#{sendEmail.locale.retrieveDisplayName()}' -jsf.contactLanguageTeamCoordinatorForLocale=\u0417\u0432\u2019\u044F\u0437\u0430\u0442\u0438\u0441\u044C \u0437 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u043E\u043C \u043A\u043E\u043C\u0430\u043D\u0434\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 '\#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()})' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.YouAreReceivingThisMailBecause=\u0412\u0438 \u043E\u0442\u0440\u0438\u043C\u0430\u043B\u0438 \u0446\u0435 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F \u0442\u043E\u043C\u0443 \u0449\u043E\: -jsf.email.GeneratedFromZanataServerAt=\u0426\u0435 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u044F \u0437\u0433\u0435\u043D\u0435\u0440\u043E\u0432\u0430\u043D\u043E \u0441\u0435\u0440\u0432\u0456\u0441\u043E\u043C Zanata \u043E\: -jsf.Account.ActivationMessage=\u041D\u0430\u0439\u0431\u043B\u0438\u0436\u0447\u0438\u043C \u0447\u0430\u0441\u043E\u043C \u0432\u0438 \u043E\u0442\u0440\u0438\u043C\u0430\u0454\u0442\u0435 \u043B\u0438\u0441\u0442 \u0437 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u043D\u0430 \u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0456\u044E \u0432\u0430\u0448\u043E\u0433\u043E \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443. -jsf.email.activation.Subject=\u0410\u043A\u0442\u0438\u0432\u0430\u0446\u0456\u044F \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443 Zanata -jsf.email.activation.register.DearName=\u0414\u043E\u0440\u043E\u0433\u0438\u0439 \#{emailServiceImpl.toName}, -jsf.email.activation.profile.DearName=\u0414\u043E\u0440\u043E\u0433\u0438\u0439 \#{profileAction.name}, -jsf.email.activation.ClickLinkToActivateAccount=\u0429\u043E\u0431 \u0430\u043A\u0442\u0438\u0432\u0443\u0432\u0430\u0442\u0438 \u0441\u0432\u0456\u0439 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 \u043F\u0435\u0440\u0435\u0439\u0434\u0456\u0442\u044C, \u0431\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0437\u0430 \u043D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u043C \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F\u043C\: -jsf.email.activation.Link=\u041F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0456\u0457 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443 -jsf.email.alternate.copyPasteMessage=\u041D\u0430\u0442\u043E\u043C\u0456\u0441\u0442\u044C \u0432\u0438 \u043C\u043E\u0436\u0435\u0442\u0435 \u0441\u043A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438 \u0442\u0430 \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u044F \u0443 \u0441\u0432\u0456\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\: -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.UrlExpireMessage=\u041F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u043D\u0435 \u043F\u0440\u0430\u0446\u044E\u0432\u0430\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 24 \u0433\u043E\u0434\u0438\u043D\u0438. -jsf.email.accountchange.Subject=\u041F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0436\u0435\u043D\u043D\u044F \u0437\u043C\u0456\u043D\u0438 Email-\u0430\u0434\u0440\u0435\u0441\u0438 \u043D\u0430 Zanata -jsf.email.accountchange.DearName=\u0414\u043E\u0440\u043E\u0433\u0438\u0439 \#{profileAction.name}, -jsf.email.accountchange.Message=\u0421\u0435\u0440\u0432\u0456\u0441 Zanata \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u0438\u0432 \u0437\u0430\u043F\u0438\u0442 \u043D\u0430 \u043E\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u044F \u0432\u0430\u0448\u043E\u0457 email \u0430\u0434\u0440\u0435\u0441\u0438 \#{profileAction.email} -jsf.email.accountchange.Message2=\u042F\u043A\u0449\u043E \u0432\u0438 \u043D\u0435 \u0432\u0438\u043A\u043E\u043D\u0443\u0432\u0430\u043B\u0438 \u0446\u044C\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0442\u0443 \u0430\u0431\u043E \u043D\u0435 \u0437\u043D\u0430\u0454\u0442\u0435, \u0447\u043E\u043C\u0443 \u0446\u0435 \u0431\u0443\u043B\u043E \u0437\u0440\u043E\u0431\u043B\u0435\u043D\u043E, \u0431\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0437\u0432\u2019\u044F\u0436\u0456\u0442\u044C\u0441\u044F \u0437 \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u0438\u043C \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C Zanata. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.accountchange.ConfirmationLink=\u041D\u0430\u0442\u0438\u0441\u043D\u0456\u0442\u044C \u0442\u0443\u0442, \u0449\u043E\u0431 \u043F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0438 e-mail \u0430\u0434\u0440\u0435\u0441\u0443 -jsf.email.usernamechange.Subject=\u0406\u043C\u2019\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 Zanata \u0431\u0443\u043B\u043E \u0437\u043C\u0456\u043D\u0435\u043D\u043E. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.usernamechange.DearName=\u0414\u043E\u0440\u043E\u0433\u0438\u0439 \#{userAction.getName(userAction.username)}, -jsf.email.usernamechange.Content=\u0412\u0430\u0448 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441 Zanata \u0431\u0443\u043B\u043E \u043D\u0435\u0434\u0430\u0432\u043D\u043E \u0437\u043C\u0456\u043D\u0435\u043D\u043E \u043E\u0434\u043D\u0438\u043C \u0437 \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u0438\u0445 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0456\u0432. \u042F\u043A\u0449\u043E \u0432\u0438 \u0446\u044C\u043E\u0433\u043E \u043D\u0435 \u043F\u0440\u043E\u0441\u0438\u043B\u0438 \u0430\u0431\u043E \u0432\u0438 \u043D\u0435 \u0432\u043F\u0435\u0432\u043D\u0435\u043D\u0456, \u0447\u043E\u043C\u0443 \u0442\u0430\u043A \u0441\u0442\u0430\u043B\u043E\u0441\u044C, \u0431\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0437\u0432\u0435\u0440\u043D\u0456\u0442\u044C\u0441\u044F \u0434\u043E \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u0438\u0445 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0456\u0432 \u043D\u0430\u0439\u0431\u043B\u0438\u0436\u0447\u0438\u043C \u0447\u0430\u0441\u043E\u043C. -jsf.email.usernamechange.YourNewUsername=\u0412\u0430\u0448\u0435 \u043D\u043E\u0432\u0435 \u0456\u043C\u2019\u044F \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 '\#{userAction.username}' -jsf.email.usernamechange.ResetPassword=\u0412\u0438 \u043C\u0430\u0454\u0442\u0435 \u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C. \u0426\u0435 \u043C\u043E\u0436\u043D\u0430 \u0437\u0440\u043E\u0431\u0438\u0442\u0438 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u044E\u0447\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F \u043D\u0438\u0436\u0447\u0435\: -jsf.email.usernamechange.ClickLinkForPasswordReset=\u041D\u0430\u0442\u0438\u0441\u043D\u0456\u0442\u044C \u0442\u0443\u0442 \u0449\u043E\u0431 \u0441\u043A\u0438\u043D\u0443\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C -jsf.email.passwordreset.Subject=\u0417\u0430\u043F\u0438\u0442 \u0441\u043A\u0438\u0434\u0430\u043D\u043D\u044F \u043F\u0430\u0440\u043E\u043B\u044E Zanata -jsf.email.passwordreset.DearName=\u0414\u043E\u0440\u043E\u0433\u0438\u0439 \#{passwordResetRequest.account.person.name}, -jsf.email.passwordreset.FollowLinkToResetPassword=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0441\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u0439\u0442\u0435\u0441\u044C \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F\u043C \u043D\u0438\u0436\u0447\u0435, \u0449\u043E\u0431 \u0441\u043A\u0438\u043D\u0443\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C \u0432\u0430\u0448\u043E\u0433\u043E \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443. -jsf.email.passwordreset.IgnoreIfNotRequested=\u042F\u043A\u0449\u043E \u0432\u0438 \u043D\u0435 \u0445\u043E\u0447\u0435\u0442\u0435 \u0441\u043A\u0438\u0434\u0430\u0442\u0438 \u043F\u0430\u0440\u043E\u043B\u044C \u2013 \u043F\u0440\u043E\u0456\u0433\u043D\u043E\u0440\u0443\u0439\u0442\u0435 \u0446\u0435\u0439 \u0437\u0430\u043F\u0438\u0442. -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.admin.SentNotification=\u0412\u0430\u0448\u0435 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F \u0432\u0456\u0434\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0443 -jsf.email.admin.SubjectPrefix=\u041B\u0438\u0441\u0442 \u0432\u0456\u0434 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 Zanata \u2013 '\#{sendEmail.fromLoginName}'\: -jsf.ZanataAdministrator=\u0410\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440 Zanata -jsf.email.admin.DearAdmin=\u0414\u043E\u0440\u043E\u0433\u0438\u0439 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0435, -jsf.email.admin.UserMessageIntro=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 Zanata '\#{sendEmail.fromName}' \u0437 ID '\#{sendEmail.fromLoginName}' \u043D\u0430\u0434\u0456\u0441\u043B\u0430\u0432 \u043D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F\: -jsf.email.ReplyInstructions=\u0412\u0438 \u043C\u043E\u0436\u0435\u0442\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0441\u0442\u0438 \#{sendEmail.fromName} \u0437\u0430 \u0430\u0434\u0440\u0435\u0441\u043E\u044E \#{sendEmail.replyEmail} -jsf.email.admin.ReceivedReason=\u0412\u0438 \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440 \u0441\u0438\u0441\u0442\u0435\u043C\u0438 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -jsf.email.admin.user.ReceivedReason=\u0412\u0438 - \u0430\u0434\u043C\u0456\u043D\u0456\u0441\u0442\u0440\u0430\u0442\u043E\u0440 -jsf.email.coordinator.SentNotification=\u0412\u0430\u0448\u0435 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F \u0431\u0443\u043B\u043E \u043D\u0430\u0434\u0456\u0441\u043B\u0430\u043D\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0456 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 \#{sendEmail.locale.retrieveNativeName()} -jsf.email.coordinator.SubjectPrefix=Zanata\: \u041A\u043E\u043C\u0430\u043D\u0434\u0430 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 \#{sendEmail.locale.localeId.id} \: \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F \u0432\u0456\u0434 '\#{sendEmail.fromLoginName}'\: -jsf.email.coordinator.DearCoordinator=\u0414\u043E\u0440\u043E\u0433\u0438\u0439 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432, -jsf.email.coordinator.UserMessageIntro=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 Zanata '\#{sendEmail.fromName}' \u0437 ID '\#{sendEmail.fromLoginName}' \u043D\u0430\u0434\u0456\u0441\u043B\u0430\u0432 \u043D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F \u043A\u043E\u043C\u0430\u043D\u0434\u0456 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 \#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()})\: -jsf.email.coordinator.ResponseInstructions=\u0412\u0438 \u043C\u043E\u0436\u0435\u0442\u0435 \u043F\u0435\u0440\u0435\u0439\u0442\u0438 \u043E\u0434\u0440\u0430\u0437\u0443 \u043D\u0430 \u0441\u0442\u043E\u0440\u0456\u043D\u043A\u0443 \u043A\u043E\u043C\u0430\u043D\u0434\u0438 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 \#{sendEmail.locale.localeId.id}. \u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u043D\u0430\u0434\u0456\u0448\u043B\u0456\u0442\u044C \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u044C \#{sendEmail.fromName} \u043D\u0430 \#{sendEmail.replyEmail} \u043F\u0456\u0441\u043B\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043D\u044F \u0432\u0438\u043A\u043E\u043D\u0430\u043D\u043D\u043D\u044F \u0439\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0442\u0443. -jsf.email.coordinator.ReceivedReason=\u0412\u0438 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440 \u0432 \u043A\u043E\u043C\u0430\u043D\u0434\u0456 \u043F\u0435\u0440\u0435\u043A\u043B\u0430\u0434\u0430\u0447\u0456\u0432 '\#{sendEmail.locale.retrieveNativeName()}' -jsf.email.group.maintainer.SentNotification=\u0412\u0430\u0448\u0435 \u043F\u043E\u0432\u0456\u0434\u043E\u043C\u043B\u0435\u043D\u043D\u044F \u043D\u0430\u0434\u0456\u0441\u043B\u0430\u043D\u043E \u0434\u043E \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440\u0430 \u0433\u0440\u0443\u043F\u0438 \#{versionGroupJoinAction.groupName} -jsf.email.maintainer.DearMaintainer=\u0428\u0430\u043D\u043E\u0432\u043D\u0438\u0439 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u043E\u0440 \u0433\u0440\u0443\u043F\u0438, -jsf.email.joingrouprequest.RequestingToJoinGroup=\u041A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447 Zanata '\#{sendEmail.fromName}' \u0437 ID '\#{sendEmail.fromLoginName}' \u0432\u0456\u0434\u0456\u0441\u043B\u0430\u0432 \u0437\u0430\u043F\u0438\u0442 \u0434\u043E\u0434\u0430\u043D\u043D\u044F \u0439\u043E\u0433\u043E/\u0457\u0457 \u0434\u043E \u0433\u0440\u0443\u043F\u0438 '\#{versionGroupJoinAction.groupName}'. -jsf.email.JoinGroupRequest.ResponseInstructions=\u0421\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u0439\u0442\u0435\u0441\u044C \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F\u043C \u043D\u0438\u0436\u0447\u0435, \u0449\u043E\u0431 \u0432\u0438\u043A\u043E\u043D\u0430\u0442\u0438 \u0437\u0430\u043F\u0438\u0442. \u041D\u0430\u043F\u0438\u0448\u0438\u0442\u044C, \u0431\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \#{sendEmail.fromName} \u043D\u0430 \#{sendEmail.replyEmail} \u043A\u043E\u043B\u0438 \u0432\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0435 \u0440\u043E\u0437\u0433\u043B\u044F\u0434 \u0446\u044C\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0442\u0443. -jsf.email.group.maintainer.ReceivedReason=\u0412\u0438 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043E\u0440 \u0433\u0440\u0443\u043F\u0438 '\#{versionGroupJoinAction.groupName}' -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -up=\u2191 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -down=\u2193 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -left=\u2039 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -right=\u203A -org.jboss.seam.loginFailed=\u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u0432\u0456\u0439\u0442\u0438 -org.jboss.seam.loginSuccessful=\u0412\u0456\u0442\u0430\u0454\u043C\u043E, \#0\! -org.jboss.seam.NotLoggedIn=\u0421\u043F\u0435\u0440\u0448\u0443 \u0443\u0432\u0456\u0439\u0434\u0456\u0442\u044C, \u0431\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430 -org.jboss.seam.TransactionFailed=\u041E\u043F\u0435\u0440\u0430\u0446\u0456\u044F \u043D\u0435 \u0432\u0438\u043A\u043E\u043D\u0430\u043D\u0430 -org.jboss.seam.NoConversation=\u041E\u0431\u0433\u043E\u0432\u043E\u0440\u0435\u043D\u043D\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E. \u0412\u0438\u0439\u0448\u043E\u0432 \u0447\u0430\u0441 \u043E\u0447\u0456\u043A\u0443\u0432\u0430\u043D\u043D\u044F \u0430\u0431\u043E \u0432\u0438\u043A\u043E\u043D\u0430\u043D\u043E \u0456\u043D\u0448\u0438\u0439 \u0437\u0430\u043F\u0438\u0442 -org.jboss.seam.IllegalNavigation=\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u043D\u0430\u0432\u0456\u0433\u0430\u0446\u0456\u0457 -org.jboss.seam.ProcessEnded=\u041F\u0440\u043E\u0446\u0435\u0441 \#0 \u0443\u0436\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -org.jboss.seam.ProcessNotFound=\u041F\u0440\u043E\u0446\u0435\u0441 \#0 \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E -org.jboss.seam.TaskEnded=\u0417\u0430\u0432\u0434\u0430\u043D\u043D\u044F \#0 \u0432\u0436\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -org.jboss.seam.TaskNotFound=\u0417\u0430\u0432\u0434\u0430\u043D\u043D\u044F \#0 \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.component.UIInput.CONVERSION=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043D\u0435 \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u043F\u0435\u0440\u0435\u0442\u0432\u043E\u0440\u0435\u043D\u0435 \u0434\u043E \u043E\u0447\u0456\u043A\u0443\u0432\u0430\u043D\u043E\u0433\u043E \u0442\u0438\u043F\u0443 -javax.faces.component.UIInput.REQUIRED=\u043E\u0431\u0432\u2019\u044F\u0437\u043A\u043E\u0432\u0435 \u043F\u043E\u043B\u0435 -javax.faces.component.UIInput.UPDATE=\u0441\u0442\u0430\u043B\u0430\u0441\u044C \u043F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0440\u0438 \u043E\u0431\u0440\u043E\u0431\u0446\u0456 \u043D\u0430\u0434\u0430\u043D\u043E\u0457 \u0456\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0456\u0457 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.component.UISelectOne.INVALID=\u043D\u0435\u0434\u0456\u0439\u0441\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.component.UISelectMany.INVALID=\u043D\u0435\u0434\u0456\u0439\u0441\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.BigDecimalConverter.DECIMAL=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0435\u0441\u044F\u0442\u043A\u043E\u0432\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0437\u0456 \u0437\u043D\u0430\u043A\u043E\u043C \u0442\u0430\u043C \u043C\u0456\u0441\u0442\u0438\u0442\u0438\u0442\u0438 \u0432\u0456\u0434 \u043E\u0434\u043D\u043E\u0433\u043E \u0437\u043D\u0430\u043A\u0443 \u043F\u0456\u0441\u043B\u044F \u0434\u0435\u0441\u044F\u0442\u043A\u043E\u0432\u043E\u0457 \u043A\u0440\u0430\u043F\u043A\u0438, \u0430\u0431\u043E \u0437\u043E\u0432\u0441\u0456\u043C \u043D\u0435 \u043C\u0456\u0441\u0442\u0438\u0442\u0438 \u0434\u0435\u0441\u044F\u0442\u043A\u043E\u0432\u0438\u0445 \u0437\u043D\u0430\u043A\u0456\u0432, \u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434 {1} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.BigIntegerConverter.BIGINTEGER=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0437\u0456 \u0437\u043D\u0430\u043A\u043E\u043C \u0442\u0430\u043C \u043C\u0456\u0441\u0442\u0438\u0442\u0438\u0442\u0438 \u043E\u0434\u043D\u0443 \u0430\u0431\u043E \u0431\u0456\u043B\u044C\u0448\u0435 \u0446\u0438\u0444\u0440 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.BooleanConverter.BOOLEAN=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 true \u0430\u0431\u043E false -javax.faces.converter.BooleanConverter.BOOLEAN_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 true \u0430\u0431\u043E false (\u0431\u0443\u0434\u044C-\u044F\u043A\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043E\u043A\u0440\u0456\u043C true, \u0431\u0443\u0434\u0435 \u043E\u0446\u0456\u043D\u044E\u0432\u0430\u0442\u0438\u0441\u044C \u044F\u043A false) -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.ByteConverter.BYTE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C \u0432\u0456\u0434 0 \u0434\u043E 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.ByteConverter.BYTE_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C \u0432\u0456\u0434 0 \u0434\u043E 255 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.CharacterConverter.CHARACTER=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u043C -javax.faces.converter.CharacterConverter.CHARACTER_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432\u0456\u0440\u043D\u0438\u043C ASCII \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.DateTimeConverter.DATE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0430\u0442\u043E\u044E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.DateTimeConverter.DATE_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0430\u0442\u043E\u044E, \u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434. {1} -javax.faces.converter.DateTimeConverter.TIME=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0430\u0442\u043E\u044E -javax.faces.converter.DateTimeConverter.TIME_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0430\u0441\u043E\u043C, \u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434. {1} -javax.faces.converter.DateTimeConverter.DATETIME=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0430\u0442\u043E\u044E \u0442\u0430 \u0447\u0430\u0441\u043E\u043C -javax.faces.converter.DateTimeConverter.DATETIME_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0430\u0442\u043E\u044E \u0442\u0430 \u0447\u0430\u0441\u043E\u043C, \u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434. {1} -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=\u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0442\u0432\u043E\u0440\u0435\u043D\u043D\u044F \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432\u043A\u0430\u0437\u0430\u043D\u043E \u0448\u0430\u0431\u043B\u043E\u043D \u0430\u0431\u043E \u0442\u0438\u043F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.DoubleConverter.DOUBLE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.DoubleConverter.DOUBLE_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C \u0432\u0456\u0434 4.9E-324 \u0434\u043E 1.7976931348623157E308 -javax.faces.converter.EnumConverter.ENUM=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u0435\u0440\u0435\u0442\u0432\u043E\u0440\u044E\u0432\u0430\u043D\u0438\u043C \u0434\u043E \u0441\u043F\u0438\u0441\u043A\u0443 -javax.faces.converter.EnumConverter.ENUM_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u0435\u0440\u0435\u0442\u0432\u043E\u0440\u044E\u0432\u0430\u043D\u0438\u043C \u0434\u043E \u0441\u043F\u0438\u0441\u043A\u0443 \u0430\u0431\u043E \u0437\u0456 \u0441\u043F\u0438\u0441\u043A\u0443, \u0449\u043E \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043A\u043E\u043D\u0441\u0442\u0430\u043D\u0442\u0443 {1} -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u0435\u0440\u0435\u0442\u0432\u043E\u0440\u044E\u0432\u0430\u043D\u0438\u043C \u0434\u043E \u0441\u043F\u0438\u0441\u043A\u0443 \u0430\u0431\u043E \u0437\u0456 \u0441\u043F\u0438\u0441\u043A\u0443, \u043F\u0440\u043E\u0442\u0435 \u0436\u043E\u0434\u043D\u043E\u0433\u043E \u043A\u043B\u0430\u0441\u0443 \u0441\u043F\u0438\u0441\u043A\u0456\u0432 \u043D\u0435 \u043D\u0430\u0434\u0430\u043D\u043E -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u0435\u0440\u0435\u0442\u0432\u043E\u0440\u044E\u0432\u0430\u043D\u0438\u043C \u0434\u043E \u0441\u043F\u0438\u0441\u043A\u0443 \u0430\u0431\u043E \u0437\u0456 \u0441\u043F\u0438\u0441\u043A\u0443, \u043F\u0440\u043E\u0442\u0435 \u0436\u043E\u0434\u043D\u043E\u0433\u043E \u043A\u043B\u0430\u0441\u0443 \u0441\u043F\u0438\u0441\u043A\u0456\u0432 \u043D\u0435 \u043D\u0430\u0434\u0430\u043D\u043E -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.FloatConverter.FLOAT=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.FloatConverter.FLOAT_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E \u0432\u0456\u0434 1.4E-45 \u0434\u043E 3.4028235E38 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.IntegerConverter.INTEGER=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.IntegerConverter.INTEGER_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0432\u0456\u0434 -2147483648 \u0434\u043E 2147483647 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.LongConverter.LONG=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.LongConverter.LONG_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C \u0432\u0456\u0434 -9223372036854775808 \u0434\u043E 9223372036854775807 -javax.faces.converter.NumberConverter.CURRENCY=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0441\u0443\u043C\u043E\u044E \u0443 \u0432\u0430\u043B\u044E\u0442\u0456 -javax.faces.converter.NumberConverter.CURRENCY_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0441\u0443\u043C\u043E\u044E \u0443 \u0432\u0430\u043B\u044E\u0442\u0456, \u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434 {1} -javax.faces.converter.NumberConverter.PERCENT=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432\u0456\u0434\u0441\u043E\u0442\u043A\u043E\u043C -javax.faces.converter.NumberConverter.PERCENT_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432\u0456\u0434\u0441\u043E\u0442\u043A\u043E\u043C, \u043D\u0430\u043F\u0440\u0438\u043A\u043B\u0430\u0434. {1} -# translation auto-copied from project Zanata server, version master, document zanata-war/src/main/resources/messages, author Maks -javax.faces.converter.NumberConverter.NUMBER=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.NumberConverter.NUMBER_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.NumberConverter.PATTERN=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.NumberConverter.PATTERN_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.ShortConverter.SHORT=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.converter.ShortConverter.SHORT_detail=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0432\u0456\u0434 -32768 \u0434\u043E 32767 -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.validator.DoubleRangeValidator.MAXIMUM=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043C\u0435\u043D\u0448\u0435 \u0430\u0431\u043E \u0440\u0456\u0432\u043D\u0435 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.validator.DoubleRangeValidator.MINIMUM=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0431\u0456\u043B\u044C\u0448\u0435 \u0430\u0431\u043E \u0440\u0456\u0432\u043D\u0435 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432 \u043F\u0440\u043E\u043C\u0456\u0436\u043A\u0443 \u0432\u0456\u0434 {0} \u0434\u043E {1} -javax.faces.validator.DoubleRangeValidator.TYPE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u043D\u0435\u043A\u043E\u0440\u0435\u043A\u0442\u043D\u0438\u0439 \u0442\u0438\u043F -javax.faces.validator.LengthValidator.MAXIMUM=\u0434\u043E\u0432\u0436\u0438\u043D\u0430 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043C\u0435\u043D\u0448\u043E\u044E \u0430\u0431\u043E \u0440\u0456\u0432\u043D\u043E\u044E {0} \u0441\u0438\u043C\u0432\u043E\u043B\u0430\u043C -javax.faces.validator.LengthValidator.MINIMUM=\u0434\u043E\u0432\u0436\u0438\u043D\u0430 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0431\u0456\u043B\u044C\u0448\u043E\u044E \u0430\u0431\u043E \u0440\u0456\u0432\u043D\u043E\u044E {0} \u0441\u0438\u043C\u0432\u043E\u043B\u0430\u043C -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.validator.LongRangeValidator.MAXIMUM=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043C\u0435\u043D\u0448\u0435 \u0430\u0431\u043E \u0440\u0456\u0432\u043D\u0435 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.validator.LongRangeValidator.MINIMUM=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0431\u0456\u043B\u044C\u0448\u0435 \u0430\u0431\u043E \u0440\u0456\u0432\u043D\u0435 {0} -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432 \u043F\u0440\u043E\u043C\u0456\u0436\u043A\u0443 \u0432\u0456\u0434 {0} \u0434\u043E {1} -javax.faces.validator.LongRangeValidator.TYPE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u043D\u0435\u0432\u0456\u0440\u043D\u0438\u0439 \u0442\u0438\u043F -# translation auto-copied from project Zanata, version jsf-pages, document main/resources/messages, author Maks -javax.faces.validator.NOT_IN_RANGE=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0432 \u043F\u0440\u043E\u043C\u0456\u0436\u043A\u0443 \u0432\u0456\u0434 {0} \u0434\u043E {1} -javax.faces.converter.STRING=\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u043D\u0435 \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u043F\u0435\u0440\u0435\u0442\u0432\u043E\u0440\u0435\u043D\u0435 \u0432 \u0440\u044F\u0434\u043E\u043A diff --git a/zanata-war/src/main/resources/messages_zh_TW_Hant.properties b/zanata-war/src/main/resources/messages_zh_TW_Hant.properties deleted file mode 100644 index 6deb81f8b3..0000000000 --- a/zanata-war/src/main/resources/messages_zh_TW_Hant.properties +++ /dev/null @@ -1,610 +0,0 @@ -jsf.Zanata=Zanata -jsf.Active=\u555F\u7528\u4E2D -jsf.ReadOnly=\u552F\u8B80 -jsf.Obsolete=\u5DF2\u904E\u6642 -jsf.RecordNotFound=\u627E\u4E0D\u5230\u7D00\u9304 -jsf.DuplicatedRecord=\u5DF2\u8907\u88FD\u7684\u7D00\u9304 -jsf.AnotherUserChangedTheSameDataPleaseTryAgain=\u53E6\u4E00\u4F4D\u4F7F\u7528\u8005\u6539\u8B8A\u4E86\u76F8\u540C\u7684\u8CC7\u6599\u3002\u8ACB\u91CD\u65B0\u5617\u8A66\u3002 -jsf.YouDoNotHavePermissionToAccessThisResource=\u60A8\u6C92\u6709\u5B58\u53D6\u9019\u9805\u8CC7\u6E90\u7684\u6B0A\u9650\u3002 -jsf.YourSessionHasTimedOutPleaseTryAgain=\u60A8\u7684 session \u5DF2\u903E\u6642\u3002\u8ACB\u91CD\u65B0\u5617\u8A66\u3002 -jsf.Actions=\u52D5\u4F5C -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Add=\u65B0\u589E -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Cancel=\u53D6\u6D88 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Close=\u95DC\u9589 -jsf.CreationDate=\u5EFA\u7ACB\u65E5\u671F -# translation auto-copied from project CFSE, version sam-1.2, document app, author tchuang -jsf.Delete=\u522A\u9664 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Description=\u63CF\u8FF0 -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author snowlet -jsf.Edit=\u7DE8\u8F2F -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author tchuang -jsf.Email=\u96FB\u5B50\u90F5\u4EF6 -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults -jsf.Help=\u8AAA\u660E -jsf.HomepageContent=\u4E3B\u9801\u5167\u5BB9 -# translation auto-copied from project System-config-language, version master, document system-config-language -jsf.Language=\u8A9E\u8A00 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Name=\u540D\u7A31 -jsf.projectType=\u5C08\u6848\u985E\u578B -jsf.projectType.Description=\u5224\u5B9A\u5C08\u6848\u7531\u5BA2\u6236\u7AEF\u6216\u662F\u900F\u904E\u7DB2\u7AD9\u4E0A\u8F09\u548C\u4E0B\u8F09\u6642\uFF0C\u6703\u5982\u4F55\u88AB\u5C0D\u5F85\u3002 -jsf.projectType.DefaultBehaviour=\u5C6C\u65BC\u6B64\u5C08\u6848\u7684\u5404\u7248\u672C\u4E4B\u985E\u578B\uFF0C\u5728\u672A\u6307\u5B9A\u5176\u985E\u578B\u7684\u60C5\u6CC1\u4E0B\u5C07\u6703\u88AB\u5957\u7528\u9810\u8A2D\u985E\u578B\u3002 -jsf.projectType.NotSpecifiedBehaviour=\u82E5\u672A\u6307\u5B9A\u5C08\u6848\u985E\u578B\uFF0C\u5C07\u6703\u4F7F\u7528\u5176\u6240\u5C6C\u4E4B\u5C08\u6848\u7684\u985E\u578B\u3002 -jsf.projectType.MoreInfo=\u6B32\u53D6\u5F97\u66F4\u591A\u8CC7\u8A0A\uFF0C\u8ACB\u53C3\u95B1 https\://github.com/zanata/zanata/wiki/Project-Types -jsf.projectType.NoSelection=-- \u672A\u9078\u64C7 -- -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Remove=\u79FB\u9664 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Save=\u5132\u5B58 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Search=\u641C\u5C0B -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Status=\u72C0\u614B -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Update=\u66F4\u65B0 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Upload=\u4E0A\u50B3 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Username=\u4F7F\u7528\u8005\u540D\u7A31 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Version=\u7248\u672C -jsf.Projects=\u5C08\u6848 -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author snowlet -jsf.Groups=\u7FA4\u7D44 -jsf.Languages=\u8A9E\u8A00 -jsf.More=\u66F4\u591A -jsf.ReportAProblem=\u56DE\u5831\u554F\u984C -jsf.KnownIssues=\u5DF2\u77E5\u554F\u984C -# translation auto-copied from project DocBook locales, version 1, document locale -jsf.Glossary=\u5C0F\u8FAD\u5F59 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Administration=\u7BA1\u7406 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Register=\u8A3B\u518A -jsf.MyProfile=\u6211\u7684\u8A2D\u5B9A\u6A94 -jsf.SearchProjects=\u641C\u5C0B\u5C08\u6848 -jsf.project.search.IncludeObsoleteTooltip=\u5728\u641C\u5C0B\u4E2D\u5305\u542B\u5DF2\u904E\u6642\u7684\u5C08\u6848 -jsf.AboutZanata=\u95DC\u65BC Zanata -jsf.Documentation=\u6587\u4EF6 -jsf.Wiki=Wiki -jsf.Blog=\u90E8\u843D\u683C -# translation auto-copied from project CFSE, version sam-1.2, document app -jsf.Support=\u652F\u63F4 -jsf.IrcHelp=IRC \u5354\u52A9 -jsf.FAQ=\u5E38\u898B\u554F\u8207\u7B54 -jsf.SiteMap=\u7DB2\u7AD9\u5730\u5716 -jsf.RunningVersionInfo=\#{messages['jsf.Zanata']} version \#{applicationConfiguration.version} (\#{applicationConfiguration.buildTimestamp})\u3002 -jsf.CopyrightNotice=&\#169; 2008-12 Red Hat, Inc \u8207\u5176\u5B83\u3002 -# translation auto-copied from project DocBook locales, version 1, document locale -jsf.Home=\u8D77\u59CB\u9801 -jsf.server.EditHomePage.label=\u7DE8\u8F2F\u7DB2\u9801\u5167\u5BB9 -jsf.server.EditHomePageCode.label=\u7DE8\u8F2F\u7DB2\u9801\u7DE8\u78BC -jsf.server.EditHomePageCode.tooltip=\u5C07\u8D77\u59CB\u9801\u7DE8\u78BC\u7DE8\u8F2F\u70BA\u6C38\u7E8C\u6027\u3002\u9019\u5C0D\u65BC\u7121\u6CD5\u900F\u904E\u7DE8\u8F2F\u9801\u7DE8\u8F2F\u7684\u8D77\u59CB\u9801\u4F86\u8AAA\u76F8\u7576\u6709\u5E6B\u52A9\u3002 -jsf.EditHomePage=\u7DE8\u8F2F\u8D77\u59CB\u9801 -jsf.CreateProject=\u5EFA\u7ACB\u5C08\u6848 -jsf.FilterActiveProjects=\u7BE9\u9078\u555F\u7528\u4E2D\u7684\u5C08\u6848 -jsf.FilterReadOnlyProjects=\u7BE9\u9078\u552F\u8B80\u7684\u5C08\u6848 -jsf.FilterObsoleteProjects=\u7BE9\u9078\u904E\u6642\u7684\u5C08\u6848 -jsf.ProjectName=\u5C08\u6848\u540D\u7A31 -jsf.NoProjectExists=\u6C92\u6709\u5B58\u5728\u7684\u5C08\u6848\u3002 -jsf.SearchResultsForProjectSearch='\#{projectSearch.searchQuery}' \u7684\u641C\u5C0B\u7D50\u679C -jsf.projectSearch.searchQuery.title=\u627E\u5230\u4E86 \#{projectSearch.resultSize} \u500B\u8207 '\#{projectSearch.searchQuery}' \u67E5\u8A62\u76F8\u7B26\u7684\u5C08\u6848 -jsf.OnlyShowingFirstPagesizeResults=\u53EA\u986F\u793A\u524D \#{projectSearch.pageSize} \u9805\u7D50\u679C\u3002 -jsf.CreateANewProject=\u65B0\u5EFA\u5C08\u6848 -jsf.EditProject=\u7DE8\u8F2F\u5C08\u6848 -jsf.ProjectId=\u5C08\u6848 ID -jsf.ProjectIdExample=\u7BC4\u4F8B\uFF1Amy-project -jsf.viewSourceFiles=\u6AA2\u8996\u539F\u59CB\u6A94 -jsf.viewSourceFiles.Example=\u4EBA\u985E\u770B\u5F97\u61C2\u7684\u539F\u59CB\u6A94\u4E4B\u9023\u7D50\uFF0C\u4F8B\u5982 https\://github.com/zanata/zanata -jsf.SourceCheckoutUrl=\u539F\u59CB\u6A94\u4E0B\u8F09/\u7C3D\u51FA -jsf.SourceCheckoutUrl.Example=\u900F\u904E\u7248\u672C\u63A7\u5236\u8EDF\u9AD4\u7C3D\u51FA\u7684\u539F\u59CB\u6A94 URL\uFF0C\u4F8B\u5982 git@github.com\:zanata/zanata.git -jsf.customizedLocaleMessage=\u60A8\u662F\u5426\u5E0C\u671B\u65B0\u589E\u81EA\u8A02\u7684\u8A9E\u8A00\uFF1F -jsf.DisabledLocales=\u505C\u7528\u7684\u8A9E\u8A00 -jsf.EnabledLocales=\u555F\u7528\u7684\u8A9E\u8A00 -jsf.AddLocale=\u65B0\u589E > -jsf.RemoveLocale=< \u79FB\u9664 -jsf.RestrictRoleAccessMessage=\u60A8\u662F\u5426\u5E0C\u671B\u6B64\u5C08\u6848\u50C5\u9650\u65BC\u7279\u5B9A\u4F7F\u7528\u8005\u5B58\u53D6\uFF1F -jsf.RestrictRoleAccessTooltip=\u9650\u5236\u5C08\u6848\u5B58\u53D6\u80FD\u529B -jsf.customizedValidationMessage=\u60A8\u662F\u5426\u5E0C\u671B\u4F7F\u7528\u81EA\u8A02\u7684\u9A57\u8B49\uFF1F -jsf.ProjectVersionId=\u7248\u672C ID -jsf.ReadOnlyVersions=\u552F\u8B80\u7248\u672C -jsf.ObsoleteVersions=\u5DF2\u904E\u6642\u7684\u7248\u672C -jsf.DocumentCount=\u6587\u4EF6\uFF1A -jsf.TranslateLinks=\u7FFB\u8B6F\u9023\u7D50 -jsf.Translate=\u7FFB\u8B6F -jsf.TranslateGWTDevMode=\u7FFB\u8B6F\uFF08GWT DevMode\uFF09 -# translation auto-copied from project Indic On-screen Keyboard, version f18-1, document iok -jsf.Open=\u958B\u555F -jsf.OpenGWTDevMode=\u958B\u555F\uFF08GWT DevMode\uFF09 -jsf.ManageVersion=\u7BA1\u7406\u7248\u672C -jsf.EditVersion=\u7DE8\u8F2F\u7248\u672C -jsf.SourceDocs=\u539F\u59CB\u6587\u4EF6 -jsf.SourceDocuments=\u539F\u59CB\u6587\u4EF6 -jsf.project.EditHomePage.label=\u7DE8\u8F2F\u7DB2\u9801\u7DE8\u78BC -jsf.project.EditHomePage.tooltip=\u5C07\u5C08\u6848\u7684\u8D77\u59CB\u9801\u7DE8\u78BC\u7DE8\u8F2F\u70BA\u6C38\u7E8C\u6027\u3002\u9019\u5C0D\u65BC\u7121\u6CD5\u900F\u904E\u5C08\u6848\u7DE8\u8F2F\u9801\u7DE8\u8F2F\u7684\u8D77\u59CB\u9801\u4F86\u8AAA\u76F8\u7576\u6709\u5E6B\u52A9\u3002 -jsf.CreateVersion=\u5EFA\u7ACB\u7248\u672C -jsf.ManageMaintainers=\u7BA1\u7406\u7DAD\u8B77\u8005 -jsf.CopyTrans=\u8907\u88FD\u7FFB\u8B6F -jsf.project.CopyTransOpts.tooltip=\u8A2D\u7F6E\u6B64\u5C08\u6848\u7684 \#{messages['jsf.CopyTrans']} \u8A2D\u5B9A\u3002 -jsf.ProjectMaintainers=\u5C08\u6848\u7DAD\u8B77\u8005 -jsf.NoMaintainers=\uFF08\u672A\u5B9A\u7FA9\u7DAD\u8B77\u8005\uFF09 -jsf.project.RoleRestrictions=\u89D2\u8272\u9650\u5236 -jsf.project.ProjectRestrictedToFollowingRoles=\u6B64\u5C08\u6848\u9650\u5236\u4E0B\u5217\u4F7F\u7528\u8005\u89D2\u8272\u9032\u884C\u5B58\u53D6\uFF1A -jsf.AddProjectMaintainer=\u65B0\u589E\u5C08\u6848\u7DAD\u8B77\u8005 -jsf.AreYouSureYouWishToRemoveThisPersonAsProjectMaintainer=\u60A8\u662F\u5426\u78BA\u5B9A\u8981\u5F9E\u5C08\u6848\u7DAD\u8B77\u8005\u6E05\u55AE\u4E2D\uFF0C\u79FB\u9664\u9019\u4F4D\u4F7F\u7528\u8005\uFF1F -jsf.AddGroupMaintainer=\u65B0\u589E\u7FA4\u7D44\u7DAD\u8B77\u8005 -jsf.AreYouSureYouWishToRemoveThisPersonAsGroupMaintainer=\u60A8\u662F\u5426\u78BA\u5B9A\u8981\u5F9E\u7FA4\u7D44\u7DAD\u8B77\u8005\u6E05\u55AE\u4E2D\uFF0C\u79FB\u9664\u9019\u4F4D\u4F7F\u7528\u8005\uFF1F -jsf.YouAreNoLongerMaintainerForThisProject=\u60A8\u5DF2\u4E0D\u518D\u662F\u6B64\u5C08\u6848\u7684\u7DAD\u8B77\u8005\u3002 -jsf.project.CopyTransOpts.title=\#{messages['jsf.CopyTrans']} \u9078\u9805 -jsf.project.CopyTransOpts.saved=\#{messages['jsf.CopyTrans']} \u9078\u9805\u5DF2\u5132\u5B58\u3002 -jsf.iteration.CopyTrans.pageTitle=\#{viewAllStatusAction.projectSlug}\:\#{viewAllStatusAction.iterationSlug} \u7684 \#{messages['jsf.CopyTrans']} -jsf.iteration.CopyTrans.Condition=\u689D\u4EF6 -jsf.iteration.CopyTrans.Condition.onContentMismatch=\u5167\u5BB9\u4E0D\u76F8\u7B26\u6642\uFF1A -jsf.iteration.CopyTrans.Condition.onProjectMismatch=\u5C08\u6848\u4E0D\u76F8\u7B26\u6642\uFF1A -jsf.iteration.CopyTrans.Condition.onContextMismatch=\u5167\u6587\u4E0D\u76F8\u7B26\u6642 (resId, msgctxt)\uFF1A -jsf.iteration.CopyTrans.Condition.onDocIdMismatch=\u6587\u4EF6 ID \u4E0D\u76F8\u7B26\u6642 (\u6587\u4EF6\u540D\u7A31\u548C\u8DEF\u5F91)\uFF1A -jsf.iteration.CopyTrans.Condition.final=\u5426\u5247\uFF1A -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author tchuang -jsf.iteration.CopyTrans.Action=\u52D5\u4F5C -jsf.iteration.CopyTrans.Help.downgradeToFuzzy=\u7FFB\u8B6F\u5C07\u6703\u88AB\u8003\u616E\u91CD\u8907\u4F7F\u7528\uFF0C\u4F46\u5B83\u5C07\u6703\u88AB\u4EE5\u6A21\u7CCA\u7FFB\u8B6F\u7684\u72C0\u614B\u91CD\u8907\u4F7F\u7528\u3002\u4E4B\u5F8C\u5C07\u6703\u6AA2\u67E5\u6578\u9805\u5148\u6C7A\u689D\u4EF6\u3002 -jsf.iteration.CopyTrans.Help.ignore=\u6B64\u689D\u4EF6\u5C07\u4E0D\u6703\u88AB\u5217\u5165\u5224\u5B9A\u7FFB\u8B6F\u662F\u5426\u6703\u88AB\u91CD\u8907\u4F7F\u7528\u7684\u8003\u91CF\u3002 -# translation auto-copied from project CFSE, version sam-1.2, document app -jsf.Start=\u8D77\u59CB -jsf.iteration.CopyTrans.AlreadyStarted=\#{messages['jsf.CopyTrans']} \u5DF2\u7531 \#{copyTransManager.getCopyTransProcessHandle( copyTransAction.projectIteration ).triggeredBy} \u555F\u7528\uFF0C\u7248\u672C\u70BA \#{copyTransAction.projectIteration.slug} \u5C08\u6848\u70BA \#{copyTransAction.projectIteration.project.name}\u3002 -jsf.CopyTrans.ClickHereToViewProgress=\u8ACB\u9EDE\u6B64\u6AA2\u8996\u5B8C\u6210\u5EA6\u3002 -jsf.iteration.CopyTrans.AlreadyStarted.flash=\u67D0\u4F7F\u7528\u8005\u5DF2\u958B\u59CB\u4E86\u6B64\u7248\u672C\u7684 \#{messages['jsf.CopyTrans']}\u3002 -jsf.iteration.CopyTrans.NoDocuments=\u6B64\u5C08\u6848\u7248\u672C\u4E2D\u6C92\u6709\u6587\u4EF6\u3002 -jsf.iteration.CopyTrans.Started=\#{messages['jsf.CopyTrans']} \u5DF2\u958B\u59CB\u3002 -jsf.iteration.ShowAllLocales.title=\u60A8\u7684\u5718\u968A\u5C07\u6703\u53CD\u767D\u986F\u793A\u5728\u4E0B\u65B9\u3002 -jsf.Refresh=\u66F4\u65B0 -jsf.RefreshTable=\u66F4\u65B0\u8868\u683C -jsf.iteration.stats.OpenInWebEditor=\u958B\u555F\u65BC\u7FFB\u8B6F\u7DE8\u8F2F\u5668\u4E2D -jsf.Documents=\u6587\u4EF6 -jsf.Statistics=\u6578\u64DA -jsf.ByWords=\u4EE5\u5B57\u6578\u7D71\u8A08 -jsf.Message=\u4EE5\u8A0A\u606F\u6578\u7D71\u8A08 -jsf.stats.Total=\u7E3D\u6578\uFF1A -jsf.stats.Translated=\u5DF2\u7FFB\u8B6F\uFF1A -jsf.stats.ShortHoursSuffix=\u5C0F\u6642 -jsf.NoContent=\uFF08\u7121\u5167\u5BB9\uFF09 -jsf.LastTranslated=\u6700\u5F8C\u7FFB\u8B6F -jsf.ConfigFile=\u914D\u7F6E\u6A94\u6848 -jsf.GenerateProjectConfig=\u7522\u751F\u5C08\u6848\u914D\u7F6E\u6A94\u6848\uFF08zanata.xml\uFF09 -jsf.iteration.CopyTrans=\u8907\u88FD\u7FFB\u8B6F -jsf.iteration.CopyTrans.title=\u7531\u5176\u5B83\u76F8\u4F3C\u7684\u6587\u4EF6\u8907\u88FD\u5DF2\u6838\u51C6\u7684\u7FFB\u8B6F\u3002 -jsf.JoinedGroups=\u5DF2\u52A0\u5165\u7684\u7FA4\u7D44 -jsf.iteration.CopyTrans.inProgress=\#{messages['jsf.CopyTrans']} \u6B63\u5728\u9032\u884C\u4E2D... -jsf.iteration.CopyTrans.started=\u5DF2\u5728 \#{viewAllStatusAction.copyTransStartTime} \u524D\u7531 \#{pHandle.triggeredBy} \u8D77\u59CB -jsf.iteration.CopyTrans.estimatedTimeRemaining=\u9810\u8A08\u5269\u9918\u6642\u9593\uFF1A\#{viewAllStatusAction.copyTransEstimatedTimeLeft} -jsf.group.FindGroup=\u5C0B\u627E\u7FA4\u7D44 -jsf.NoResultToDisplay=\u6C92\u6709\u53EF\u986F\u793A\u7684\u7D50\u679C\u3002 -jsf.GroupName=\u7FA4\u7D44\u540D\u7A31 -jsf.SelectGroup=\u9078\u64C7\u7FA4\u7D44 -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults -jsf.Select=\u9078\u64C7 -jsf.pager.NextPage=\u4E0B\u4E00\u9801 -jsf.pager.PreviousPage=\u4E0A\u4E00\u9801 -jsf.iteration.files.NoFiles=\u6C92\u6709\u53EF\u7528\u7684\u6A94\u6848 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.iteration.files.Path=\u8DEF\u5F91 -jsf.iteration.files.Filter.title=\u4EE5\u6587\u4EF6\u540D\u7A31\u7BE9\u9078 -jsf.Upload.Title=\u4E0A\u50B3\u6587\u4EF6\u4EE5\u5408\u4F75/\u8986\u84CB\u76EE\u524D\u7684\u7FFB\u8B6F -jsf.iteration.files.UploadFile=\u4E0A\u50B3\u6A94\u6848 -jsf.iteration.files.Merge=\u5408\u4F75 -jsf.iteration.files.Merge.title=\u7576\u9078\u53D6\u6642\uFF0C\u76EE\u524D\u7684\u8CC7\u6599\u5C07\u6703\u8207\u4E0A\u50B3\u7684\u6587\u4EF6\u5408\u4F75\u3002\u5426\u5247\uFF0C\u8CC7\u6599\u5C07\u6703\u88AB\u4E0A\u50B3\u7684\u6587\u4EF6\u8986\u5BEB\u3002 -jsf.iteration.files.MergeCheckbox.Title=\u7576\u9078\u53D6\u6642\uFF0C\u5DF2\u66F4\u65B0\u7684\u7FFB\u8B6F\u5C07\u6703\u88AB\u5BEB\u5165\uFF0C\u5176\u5B83\u5167\u5BB9\u5247\u4FDD\u6301\u4E0D\u8B8A\u3002 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.iteration.files.Download=\u4E0B\u8F09 -jsf.iteration.files.dotpot=.pot -jsf.iteration.files.dotofflinepot=\u96E2\u7DDA .pot -jsf.iteration.files.dotofflinepot.description=\u4F7F\u7528 msgctxt \u4F86\u5132\u5B58 Zanata id \u7684\u7279\u6B8A pot \u683C\u5F0F\u3002 -jsf.iteration.files.dotofflinepot.purpose=\u9019\u50C5\u9069\u7528\u65BC\u9032\u884C\u96E2\u7DDA\u7FFB\u8B6F\u6642\uFF0C\u539F\u59CB\u6A94\u4E0D\u61C9\u4EE5\u6B64\u683C\u5F0F\u4E0A\u50B3\u3002 -jsf.iteration.files.dotpo=.po -jsf.iteration.files.dotofflinepo=\u96E2\u7DDA .po -jsf.iteration.files.dotofflinepo.description=\u4F7F\u7528 msgctxt \u4F86\u5132\u5B58 Zanata id \u7684\u7279\u6B8A po \u683C\u5F0F\u3002 -jsf.iteration.files.dotofflinepo.purpose=\u7576\u60A8\u8981\u4E0A\u8F09\u4E00\u4EFD\u539F\u672C\u4E26\u975E po \u683C\u5F0F\u6587\u4EF6\u7684 po \u7FFB\u8B6F\u6642\uFF0CZanata \u5C07\u9700\u8981\u4F7F\u7528\u6B64\u683C\u5F0F\u3002 -jsf.iteration.files.ConfirmDocDeletion=\u60A8\u662F\u5426\u78BA\u5B9A\u8981\u79FB\u9664\u6B64\u539F\u59CB\u6587\u4EF6\uFF1F -jsf.iteration.files.DocumentDeleted=\u6587\u4EF6\u5DF2\u6210\u529F\u522A\u9664\u3002 -jsf.iteration.files.ProcessDlgTitle=\u6B63\u5728\u8655\u7406\u5C08\u6848\u6A94\u6848... -jsf.iteration.files.UploadDocument=\u4E0A\u8F09\u6587\u4EF6 -jsf.SupportedUploadFormats=\u652F\u63F4\u7684\u985E\u578B\uFF1A.pot .dtd .txt .odt .fodt .odp .fodp .ods .fods .odg .fodg .odb .odf -jsf.SourceLanguage=\u539F\u59CB\u8A9E\u8A00 -jsf.iteration.files.DocumentPath=\u6587\u4EF6\u8DEF\u5F91 -jsf.ConfigFileForOfflineTranslation=\u96E2\u7DDA\u7FFB\u8B6F\u914D\u7F6E\u6A94\u6848 -jsf.GenerateProjectConfigSingleLocale=\u70BA\u6B64\u7248\u672C\u7522\u751F\u5C08\u6848\u914D\u7F6E\u6A94\u6848\uFF08zanata.xml\uFF09\uFF0C\u8A9E\u8A00\u70BA \#{projectIterationFilesAction.localeId} -jsf.GenerateProjectConfigForOfflineTranslation=\u70BA\u6B64\u7248\u672C\u7522\u751F\u5C08\u6848\u914D\u7F6E\u6A94\u6848\uFF08zanata.xml\uFF09\uFF0C\u8A9E\u8A00\u70BA \#{projectIterationFilesAction.localeId}\uFF0C\u4E26\u4E14\u4F7F\u7528\u4E86\u7279\u6B8A\u7684\u5C08\u6848\u985E\u578B 'offlinepo'\uFF0C\u4EE5\u9032\u884C po \u6A94\u6848\u7684\u96E2\u7DDA\u7FFB\u8B6F\u3002 -jsf.ConfigFileDisabledProjectNotSet=\u5DF2\u505C\u7528\uFF0C\u56E0\u70BA\u7DAD\u8B77\u8005\u5C1A\u672A\u70BA\u6B64\u5C08\u6848\u8A2D\u7F6E\u5C08\u6848\u985E\u578B\u3002 -jsf.iteration.files.DownloadAllFiles=\u4E0B\u8F09\u6240\u6709\u6A94\u6848\uFF08zip\uFF09 -jsf.iteration.files.DownloadAllFiles.title=\u4E0B\u8F09\u6240\u6709\u5DF2\u7FFB\u8B6F\u7684\u6A94\u6848\u3002 -jsf.iteration.files.DownloadAllFilesOfflinePo=\u4E0B\u8F09\u6240\u6709\u6A94\u6848\uFF08\u96E2\u7DDA po zip\uFF09 -jsf.iteration.files.DownloadAllFilesOfflinePo.title=\u4EE5 po \u683C\u5F0F\u4E0B\u8F09\u6240\u6709\u5DF2\u7FFB\u8B6F\u7684\u6A94\u6848\uFF0C\u4EE5\u9032\u884C\u96E2\u7DDA\u7FFB\u8B6F\u3002 -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotAllowed=\u5C08\u6848\u985E\u578B\u5FC5\u9808\u8A2D\u70BA 'Gettext' \u6216\u662F 'Podir'\u3002\u8ACB\u806F\u7D61\u5C08\u6848\u7DAD\u8B77\u8005\u3002 -jsf.iteration.files.DownloadAllFiles.ProjectTypeNotSet=\u5C1A\u672A\u70BA\u6B64\u91CD\u8907\u9805\u76EE\u8A2D\u7F6E\u5C08\u6848\u985E\u578B\u3002\u8ACB\u806F\u7D61\u5C08\u6848\u7DAD\u8B77\u8005\u3002 -jsf.iteration.files.ConfirmDownloadAllFiles=\u6B63\u5728\u6E96\u5099\u60A8\u7684\u4E0B\u8F09\uFF0C\u4E26\u4E14\u5B8C\u6210\u53EF\u80FD\u6703\u82B1\u4E0A\u5E7E\u5206\u9418\u3002\u662F\u5426\u7E7C\u7E8C\uFF1F -jsf.generatezip.ProgressLabel=\#{projectIterationZipFileAction.zipFilePrepHandle.maxProgress} \u4E4B \#{projectIterationZipFileAction.zipFilePrepHandle.currentProgress} -jsf.iteration.files.WhyCantITranslate=\u70BA\u4F55\u6211\u7121\u6CD5\u7FFB\u8B6F\uFF1F -jsf.iteration.files.translateDenied.NotLoggedIn=\u60A8\u5C1A\u672A\u767B\u5165\u3002 -jsf.iteration.files.translateDenied.VersionIsReadOnly=\u6B64\u5C08\u6848\u7248\u672C\u70BA\u552F\u8B80\u3002 -jsf.iteration.files.translateDenied.VersionIsObsolete=\u6B64\u5C08\u6848\u7248\u672C\u5DF2\u904E\u6642\u3002 -jsf.iteration.files.translateDenied.UserNotInProjectRole=\u60A8\u5FC5\u9808\u64C1\u6709\u9019\u4E9B\u4F7F\u7528\u8005\u89D2\u8272\uFF0C\u624D\u80FD\u7FFB\u8B6F\u6B64\u5C08\u6848\uFF1A{0} -jsf.NoGroupExists=\u6C92\u6709\u5B58\u5728\u7684\u7FA4\u7D44\u3002 -jsf.groups.ShowActiveGroups=\u986F\u793A\u555F\u7528\u4E2D\u7684\u7FA4\u7D44 -jsf.groups.ShowObsoleteGroups=\u986F\u793A\u5DF2\u904E\u6642\u7684\u7FA4\u7D44 -jsf.GroupId=\u7FA4\u7D44 ID -jsf.GroupIdExample=\u7BC4\u4F8B\uFF1Amy-group -jsf.AddProjectVersions=\u65B0\u589E\u5C08\u6848\u7248\u672C -jsf.groups.FindProjectVersion=\u5C0B\u627E\u5C08\u6848\u7248\u672C -jsf.NoResultToDisplayProjectSearch=\u6C92\u6709\u53EF\u986F\u793A\u7684\u7D50\u679C\u3002\u8ACB\u6AA2\u67E5\u6307\u5B9A\u7684\u5C08\u6848\u662F\u5426\u542B\u6709\u4EFB\u4F55\u7248\u672C\u3002 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.ManageSearch.SelectAll=\u5168\u90E8\u9078\u64C7 -jsf.AddSelected=\u52A0\u5165\u9078\u64C7\u7684\u9805\u76EE -jsf.EditGroup=\u7DE8\u8F2F\u7FA4\u7D44 -jsf.GroupMaintainers=\u7FA4\u7D44\u7DAD\u8B77\u8005 -jsf.CreateSupportedLanguage=\u65B0\u589E\u8A9E\u8A00 -jsf.NativeName=\u539F\u59CB\u540D\u7A31 -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author snowlet -jsf.Members=\u6210\u54E1 -jsf.LanguageTeamTitle=\#{languageTeamAction.locale.retrieveDisplayName()} \u5718\u968A -jsf.SizeMembers=\#{languageTeamAction.locale.members.size} \u6210\u54E1 -jsf.Coordinator=\u5354\u8ABF\u54E1 -jsf.JoinLanguageTeam=\u52A0\u5165\u8A9E\u8A00\u5718\u968A -jsf.LeaveLanguageTeam=\u96E2\u958B\u8A9E\u8A00\u5718\u968A -jsf.RequestToJoinLanguageTeam=\u8ACB\u6C42\u52A0\u5165\u5718\u968A -jsf.contactLanguageTeamCoordinator=\u806F\u7D61\u5718\u968A\u5354\u8ABF\u54E1 -jsf.AddTeamMember=\u65B0\u589E\u5718\u968A\u6210\u54E1 -jsf.FindUsersToAdd=\u5C0B\u627E\u6B32\u65B0\u589E\u7684\u4F7F\u7528\u8005 -jsf.AlreadyInTeam=\u5DF2\u5C6C\u65BC\u6B64\u5718\u968A -jsf.EditHelpPageContent=\u7DE8\u8F2F\u8AAA\u660E\u9801\u5167\u5BB9 -jsf.ContactAdmin=\u806F\u7D61\u7BA1\u7406\u54E1 -jsf.Entries=\u9805\u76EE -jsf.Glossary.supportedFileFormat=\u652F\u63F4\u7684\u6A94\u6848\u683C\u5F0F\uFF1APO \u8207 CSV -jsf.Glossary.SourceLocale.Title=\u539F\u59CB\u8A9E\u8A00\uFF08\u50C5\u9069\u7528\u65BC PO \u6A94\u6848\u683C\u5F0F\uFF09 -jsf.TargetLanguage=\u76EE\u6A19\u8A9E\u8A00 -jsf.Glossary.TargetLocale.Title=\u76EE\u6A19\u8A9E\u8A00\uFF08\u50C5\u9069\u7528\u65BC PO \u6A94\u6848\u683C\u5F0F\uFF09 -jsf.Glossary.TreatSourceCommentsAsTarget=\u662F\u5426\u8981\u5C07\u539F\u59CB\u8A3B\u89E3\u548C ref \u8996\u70BA\u76EE\u6A19\u8A3B\u89E3\uFF1F -jsf.Glossary.TreatSourceCommentsAsTarget.Title=\u7576\u9078\u53D6\u6642\uFF0C\u539F\u59CB\u8A3B\u89E3\u548C\u53C3\u7167\u5C07\u6703\u88AB\u4F7F\u7528\u4F86\u4F5C\u70BA\u76EE\u6A19\u8A3B\u89E3 -jsf.Glossary.CommentColumnNames=\u8A3B\u89E3\u6B04\u4F4D\u540D\u7A31 -jsf.Glossary.CommentColumnNames.Title=\u5DF2\u81EA\u8A02\u4E86\u7528\u65BC csv \u6A94\u6848\u683C\u5F0F\u7684\u8A3B\u89E3\u6B04\u4F4D\u8868\u982D\u3002CSV \u7684\u683C\u5F0F\uFF1A{source locale},{locale1},{locale2},...,{pos},{description} \u6216\u662F {source locale},{locale},{locale},...,{description1},{description2},... \uFF08\u50C5\u9069\u7528\u65BC CSV \u6A94\u6848\u683C\u5F0F\uFF09 -jsf.ThisActionCannotBeUndone=\u7121\u6CD5\u5FA9\u539F\u6B64\u52D5\u4F5C -jsf.SelectLocaleToDelete=\u9078\u64C7\u6B32\u522A\u9664\u7684\u8A9E\u8A00 -jsf.SignUp=\u8A3B\u518A -jsf.NameToolTip=\u540D\u7A31\u7684\u7B2C\u4E00\u500B\u5B57\u6BCD\u5FC5\u9808\u662F\u5927\u5BEB\u3002 -jsf.EmailToolTip=\u96FB\u5B50\u90F5\u4EF6\u683C\u5F0F\u61C9\u70BA username@domain.name\u3002 -jsf.UsernameToolTip=\u4F7F\u7528\u8005\u540D\u7A31\u5FC5\u9808\u5168\u90E8\u5C0F\u5BEB\u3002 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Password=\u5BC6\u78BC -# translation auto-copied from project CFSE, version sam-1.2, document app -jsf.ConfirmPassword=\u78BA\u8A8D\u5BC6\u78BC -jsf.IAgreeToThe=\u63A5\u53D7 -# translation auto-copied from project CFSE, version 1.1, document app -jsf.TermsOfUse=\u4F7F\u7528\u689D\u6B3E -jsf.register.LoginUsingOpenId=\u60A8\u4EA6\u53EF\u5728\u6B64\u4F7F\u7528 Open ID \u767B\u5165\u3002 -jsf.PleaseContactAdministrationToGetRegistrationLink=\u8ACB\u806F\u7D61\u7BA1\u7406\u54E1\u4EE5\u53D6\u5F97\u8A3B\u518A\u9023\u7D50\u3002 -jsf.ForgotYourPassword=\u5FD8\u8A18\u4E86\u60A8\u7684\u5BC6\u78BC\uFF1F -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.ResetPassword=\u91CD\u8A2D\u5BC6\u78BC -jsf.SubmitRequest=\u63D0\u4EA4\u8ACB\u6C42 -jsf.ResetYourPassword=\u91CD\u8A2D\u60A8\u7684\u5BC6\u78BC -jsf.NewPassword=\u65B0\u5BC6\u78BC -jsf.OldPassword=\u820A\u5BC6\u78BC -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.ChangePassword=\u66F4\u6539\u5BC6\u78BC -# translation auto-copied from project CFSE, version 1.0.1, document app, author snowlet -jsf.RememberMe=\u8A18\u4F4F\u6211 -jsf.login.openid.SelectProvider=\u60A8\u5982\u4F55\u767B\u5165\uFF1F -jsf.login.openid.fedora=Fedora \u4F7F\u7528\u8005\u540D\u7A31 -jsf.login.openid.myopenid=MyOpenID \u4F7F\u7528\u8005 -jsf.login.openid.yahoo=Yahoo \u4F7F\u7528\u8005\u540D\u7A31 -jsf.login.openid=Open ID -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.login.internal=\u4F7F\u7528\u8005\u540D\u7A31 -jsf.UsernameNotAvailable=\u4F7F\u7528\u8005\u540D\u7A31 "\#{userAction.username}" \u4E0D\u5B58\u5728 -jsf.FedoraUsername=Fedora \u4F7F\u7528\u8005\u540D\u7A31 -jsf.ActivateAccount=\u555F\u7528\u5E33\u865F -jsf.ValidateEmail=\u9A57\u8B49\u96FB\u5B50\u90F5\u4EF6 -jsf.InactiveAccount=\u505C\u7528\u5E33\u865F -jsf.inactiveaccount.PleaseSelectOne=\u60A8\u7684\u5E33\u865F\u5C1A\u672A\u555F\u7528\u3002\u8ACB\u9078\u64C7\u4E0B\u5217\u9078\u9805\u4E4B\u4E00\uFF1A -jsf.ResendActivationEmail=\u91CD\u65B0\u50B3\u9001\u555F\u7528\u96FB\u5B50\u90F5\u4EF6 -jsf.or=\u6216\u662F -jsf.inactiveaccount.UpdateAndResend=\u66F4\u65B0\u96FB\u5B50\u90F5\u4EF6\u5730\u5740\u4E26\u91CD\u65B0\u50B3\u9001\u555F\u7528\u96FB\u5B50\u90F5\u4EF6\uFF1A -jsf.UpdateEmail=\u66F4\u65B0\u96FB\u5B50\u90F5\u4EF6\u5730\u5740 -jsf.InvalidActivationKey=\u555F\u52D5\u91D1\u9470\u7121\u6548 -jsf.ActivationLinkExpired=\u555F\u52D5\u9023\u7D50\u5DF2\u904E\u671F\u3002\u8ACB\u767B\u5165\u4E26\u9EDE\u9078 "\#{messages['jsf.ResendActivationEmail']}"\u3002 -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author snowlet -jsf.Error=\u932F\u8AA4 -jsf.ErrorTitle=\u76EE\u524D\u7684\u932F\u8AA4\uFF1A -# translation auto-copied from project CFSE, version sam-1.2, document app, author tchuang -jsf.NoErrors=\u7121\u932F\u8AA4 -jsf.EditProfile=\u7DE8\u8F2F\u8A2D\u5B9A\u6A94 -jsf.ManageIdentities=\u7BA1\u7406\u8EAB\u4EFD -jsf.identities.MergeAccount=\u5408\u4F75\u5E33\u865F -jsf.identities.MergeAccount.tootip=\u82E5\u60A8\u5E0C\u671B\u5C07\u5169\u500B Zanata \u5E33\u865F\u5408\u4F75\u70BA\u55AE\u4E00\u5E33\u865F\uFF0C\u8ACB\u4F7F\u7528\u6B64\u9078\u9805\u3002 -jsf.ApiKey=API \u91D1\u9470 -jsf.YourCurrentApiKeyIs=\u60A8\u76EE\u524D\u7684 API \u91D1\u9470\u70BA -jsf.NotGenerated=\uFF08\u5C1A\u672A\u7522\u751F\uFF09 -jsf.apikey.ConfirmGenerate=\u662F\u5426\u78BA\u8A8D\u8981\u7522\u751F\u60A8\u7684 API \u91D1\u9470\uFF1F -jsf.ConfigurationForZanataini=\u914D\u7F6E [zanata.ini] -jsf.MaintainedProjects=\u7DAD\u8B77\u7684\u5C08\u6848 -jsf.LanguageTeams=\u8A9E\u8A00\u5718\u968A -jsf.MaintainedGroups=\u7DAD\u8B77\u7684\u7FA4\u7D44 -jsf.FirstExternalLoginMessage=\u8ACB\u5728\u4EE5\u4E0B\u9A57\u8B49\u96FB\u5B50\u90F5\u4EF6\u5730\u5740\uFF0C\u4E26\u9EDE\u9078\u300C\u5132\u5B58\u300D\u4EE5\u9A57\u8B49\u60A8\u7684\u96FB\u5B50\u90F5\u4EF6\u3002 -jsf.AccountDetails=\u5E33\u865F\u8A73\u7D30\u8CC7\u6599 -jsf.identities.Title=\u8EAB\u4EFD -jsf.identities.ConfirmIdentityRemoval=\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u79FB\u9664\u6B64\u8EAB\u4EFD\uFF1F\u60A8\u5C07\u7121\u6CD5\u4F7F\u7528\u6B64\u8EAB\u4EFD\u767B\u5165\u3002 -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys, author snowlet -jsf.identities.Type=\u985E\u578B -jsf.identities.User=\u8EAB\u4EFD -jsf.identities.AddIdentity=\u65B0\u589E\u8EAB\u4EFD -jsf.identities.Verify=\u9A57\u8B49\u8EAB\u4EFD -jsf.profile.MergeAccount=\u5408\u4F75\u5E33\u865F -jsf.profile.MergeAccount.info=\u8ACB\u767B\u5165\u60A8\u5E0C\u671B\u5408\u4F75\u7684\u5E33\u865F\u3002\u60A8\u5C07\u9700\u8981\u4F7F\u7528\u4EE5\u4E0B\u5176\u4E2D\u4E00\u9805\u8A8D\u8B49\u65B9\u5F0F\u3002\u5728\u9019\u4E4B\u5F8C\u60A8\u5C07\u6703\u88AB\u8981\u6C42\u9032\u884C\u78BA\u8A8D\u3002 -jsf.profile.MergeAccount.confirm=\u78BA\u8A8D -jsf.profile.MergeAccount.confirmationMessage=\u60A8\u5373\u5C07\u5728\u4EE5\u4E0B\u5E33\u865F\u4E2D\u9032\u884C\u5408\u4F75\uFF1A

\u4F7F\u7528\u8005\u540D\u7A31\uFF1A\#{accountMergeAction.obsoleteAccount.username}
\u540D\u7A31\uFF1A\#{accountMergeAction.obsoleteAccount.person.name}
\u96FB\u5B50\u90F5\u4EF6\uFF1A\#{accountMergeAction.obsoleteAccount.person.email}

\u6B64\u8B8A\u66F4\u4E43\u6C38\u4E45\u6027\u4E26\u4E14\u7121\u6CD5\u9084\u539F\u3002

\u4EE5\u4E0A\u63D0\u5230\u7684\u5E33\u865F\u5C07\u6703\u88AB\u505C\u7528\uFF0C\u4E26\u4E14\u5176\u6240\u6709\u6B0A\u9650\u5C07\u6703\u88AB\u8A3B\u92B7\u3002\u60A8\u76EE\u524D\u7684\u5E33\u865F\u5C07\u6703\u7E7C\u627F\u6240\u6709\u7684\u6B0A\u9650\u3002

\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u9019\u9EBC\u505A\uFF1F -jsf.ServerConfiguration=\u4F3A\u670D\u5668\u914D\u7F6E -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults -jsf.ManageUsers=\u7BA1\u7406\u4F7F\u7528\u8005 -jsf.ManageRoles=\u7BA1\u7406\u89D2\u8272 -jsf.ManageLanguage=\u7BA1\u7406\u8A9E\u8A00 -jsf.ManageSearch=\u7BA1\u7406\u641C\u5C0B -jsf.OverallStatistics=\u6574\u9AD4\u6578\u64DA -jsf.RoleAssignmentRules=\u89D2\u8272\u5206\u914D\u898F\u5247 -jsf.ServerMonitoring=\u4F3A\u670D\u5668\u76E3\u63A7 -jsf.ProcessManager=\u7A0B\u5E8F\u7BA1\u7406\u54E1 -jsf.ServerUrl=\u4F3A\u670D\u5668 URL -jsf.UrlToolTip=\u4F3A\u670D\u5668\u7684\u57FA\u790E URL\uFF0C\u5305\u62EC\u61C9\u7528\u7A0B\u5F0F\u5167\u5BB9\u8DEF\u5F91\uFF08\u6C92\u6709\u5F8C\u65B9\u7684\u6B63\u659C\u7DDA\uFF09 -jsf.UrlExample=\u4F8B\u5982 http\://example.com/zanata or http\://zanata.example.com -jsf.RegisterUrl=\u8A3B\u518A URL -jsf.RegisterUrlToolTip=\u4F3A\u670D\u5668\u7684\u4F7F\u7528\u8005\u8A3B\u518A URL -jsf.RegisterUrlExample=\u4F8B\u5982 /zanata/account/register or http\://example.com/register -jsf.EmailDomainName=\u96FB\u5B50\u90F5\u4EF6\u5340\u57DF\u540D\u7A31 -jsf.EmailDomainNameToolTip=\u96FB\u5B50\u90F5\u4EF6\u5340\u57DF\u540D\u7A31\u7684\u683C\u5F0F\u61C9\u70BA example.com\u3002 -jsf.EmailDomainNameExample=\u4F8B\u5982 redhat.com -jsf.config.AdminEmail=\u806F\u7D61\u7BA1\u7406\u54E1\u5730\u5740 -jsf.config.AdminEmail.tooltip=\u7576\u4F7F\u7528\u300C\u806F\u7D61\u7BA1\u7406\u54E1\u300D\u8868\u683C\u6642\uFF0C\u96FB\u5B50\u90F5\u4EF6\u5C07\u6703\u88AB\u50B3\u9001\u81F3\u9019\u4E9B\u5730\u5740\u3002 -jsf.config.AdminEmail.DoesNotChangeUserEmail=\u6B64\u6B04\u4F4D\u4E0D\u6703\u6539\u8B8A\u4EFB\u4F55\u7BA1\u7406\u4F7F\u7528\u8005\u7684\u500B\u5225\u96FB\u5B50\u90F5\u4EF6\u5730\u5740\u3002 -jsf.email.EmailListToolTip=\u96FB\u5B50\u90F5\u4EF6\u5730\u5740\u61C9\u4EE5\u55AE\u4E00\u9017\u865F\uFF08,\uFF09\u5340\u9694\u958B\u4F86 -jsf.config.FromEmailAddr=\u5BC4\u4EF6\u8005\u90F5\u4EF6\u5730\u5740 -jsf.config.FromEmailAddr.tooltip=\u9019\u5C07\u6703\u88AB\u4F7F\u7528\u5728\u4EFB\u4F55\u7531\u6B64 zanata \u4F3A\u670D\u5668\u50B3\u9001\u7684\u96FB\u5B50\u90F5\u4EF6\u7684\u300C\u5BC4\u4EF6\u8005\u300D\u6B04\u4F4D\u4E2D -jsf.config.EnableLogEmails=\u555F\u7528\u65E5\u8A8C\u96FB\u5B50\u90F5\u4EF6 -jsf.config.EnableLogEmails.tooltip=\u555F\u7528\u6216\u505C\u7528\u900F\u904E\u96FB\u5B50\u90F5\u4EF6\u50B3\u9001 Zanata \u8A3A\u65B7\u65E5\u8A8C\u8CC7\u8A0A\u3002 -jsf.config.LogDestEmail=\u65E5\u8A8C\u76EE\u6A19\u96FB\u5B50\u90F5\u4EF6\u5730\u5740 -jsf.config.LogDestEmail.tooltip=\u7576\u767C\u751F\u8A18\u9304\u4E8B\u4EF6\u6642\uFF0C\u96FB\u5B50\u90F5\u4EF6\u5C07\u6703\u88AB\u50B3\u9001\u5230\u9019\u4E9B\u5730\u5740\u3002 -jsf.config.LogEmailLevel=\u96FB\u5B50\u90F5\u4EF6\u65E5\u8A8C\u7B49\u7D1A -jsf.config.LogEmailLevel.tooltip=\u900F\u904E\u96FB\u5B50\u90F5\u4EF6\u50B3\u9001\u7684\u65E5\u8A8C\u7B49\u7D1A\u3002\u6BD4\u65B9\u8AAA\u932F\u8AA4\u53EA\u6703\u50B3\u9001\u932F\u8AA4\u8A0A\u606F\uFF0C\u800C\u8B66\u544A\u5247\u6703\u50B3\u9001\u8B66\u544A\u548C\u932F\u8AA4\u8A0A\u606F\u3002 -# translation auto-copied from project CFSE, version sam-1.2, document app, author tchuang -jsf.Warning=\u8B66\u544A -jsf.config.PiwikUrl=Piwik URL -jsf.config.Piwiktooltip=Piwik \u8A3A\u65B7\u5DE5\u5177 URL\u3002\u4F8B\u5982 http\://localhost/piwik -jsf.config.PiwikIdSite=Piwik Id -jsf.config.PiwikIdSitetooltip=Piwik \u4E2D\u7684\u7DB2\u7AD9 ID -jsf.CreateNewUser=\u65B0\u5EFA\u4F7F\u7528\u8005 -jsf.MemberOf=\u6210\u54E1\u96B8\u5C6C\u65BC -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys -jsf.Enabled=\u5DF2\u555F\u7528 -jsf.AreYouSureYouWishToDeleteThisUserThisActionCannotBeUndone=\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u522A\u9664\u9019\u4F4D\u4F7F\u7528\u8005\uFF1F\u6B64\u52D5\u4F5C\u7121\u6CD5\u5FA9\u539F\u3002 -jsf.UserManager.delete.constraintViolation.error=\u7121\u6CD5\u5C07\u9019\u4F4D\u4F7F\u7528\u8005\u7531\u7CFB\u7D71\u4E0A\u79FB\u9664\u3002\u60A8\u53EF\u505C\u7528\u9019\u4F4D\u4F7F\u7528\u8005\u4F86\u4EE3\u66FF\u79FB\u9664\u3002 -jsf.AccountEnabled=\u5E33\u865F\u5DF2\u555F\u7528 -jsf.CreateRole=\u5EFA\u7ACB\u89D2\u8272 -jsf.AreYouSureYouWishToDeleteThisRoleThisActionCannotBeUndone=\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u522A\u9664\u6B64\u89D2\u8272\uFF1F\u9019\u9805\u52D5\u4F5C\u7121\u6CD5\u5FA9\u539F\u3002 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.Role=\u89D2\u8272 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.RoleDetails=\u89D2\u8272\u7684\u8A73\u7D30\u8CC7\u6599 -jsf.EnabledByDefault=\u5C31\u9810\u8A2D\u503C\u555F\u7528 -jsf.AreYouSureYouWishToDeleteThisLanguageThisActionCannotBeUndone=\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u522A\u9664\u6B64\u8A9E\u8A00\uFF1F\u9019\u9805\u52D5\u4F5C\u7121\u6CD5\u5FA9\u539F\u3002 -jsf.AreYouSureYouWishToEnableThisLanguage=\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u555F\u7528\u6B64\u8A9E\u8A00\uFF1F -jsf.AreYouSureYouWishToDisableThisLanguage=\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u505C\u7528\u6B64\u8A9E\u8A00\uFF1F -jsf.language.manager.DisableByDefaultConfirmation=\u60A8\u662F\u5426\u78BA\u8A8D\u5C31\u9810\u8A2D\u503C\u8981\u505C\u7528\u6B64\u8A9E\u8A00\uFF1F -jsf.language.manager.EnableByDefaultConfirmation=\u60A8\u662F\u5426\u78BA\u8A8D\u5C31\u9810\u8A2D\u503C\u8981\u555F\u7528\u6B64\u8A9E\u8A00\uFF1F -jsf.TeamMembers=\u5718\u968A\u6210\u54E1 -jsf.language.validation.ReplaceUnderscores=\u66FF\u63DB\u5B83\u5011\u3002 -jsf.language.validation.Underscores=\u5E95\u7DDA\u7B26\u865F\u61C9\u53D6\u4EE3\u70BA\u9023\u5B57\u7B26\u865F\u3002 -jsf.CountryCode=\u570B\u78BC -jsf.LanguageCode=\u8A9E\u8A00\u7DE8\u78BC -jsf.Variant=\u8B8A\u9AD4 -jsf.language.validation.Invalid=\u7121\u6548\u7684\u8A9E\u8A00\u540D\u7A31 -jsf.language.validation.Existing=\u6B64\u8A9E\u8A00\u5DF2\u5B58\u5728 -jsf.language.validation.UnknownPluralForm=\u8B66\u544A\uFF1A\u6C92\u6709\u53EF\u7528\u7684\u8907\u6578\u8CC7\u8A0A\u3002\u5047\u8A2D\u7121\u8907\u6578\u3002 -jsf.language.validation.SimilarLocaleFound=\u767C\u73FE\u4E86\u76F8\u4F3C\u7684\u8A9E\u8A00\uFF1A -jsf.manageSearch.AllActions=\uFF08\u6240\u6709\u52D5\u4F5C\uFF09 -# translation auto-copied from project DocBook locales, version 1, document locale -jsf.manageSearch.Table=\u8868\u683C -jsf.manageSearch.AllTables=\uFF08\u6240\u6709\u8868\u683C\uFF09 -jsf.manageSearch.purge=\u6E05\u9664\u7D22\u5F15 -jsf.manageSearch.purge.Description=\u5C07\u8868\u683C\u7684\u65E2\u6709\u7D22\u5F15\u9805\u76EE\u6A19\u8A18\u70BA\u904E\u6642\u3002 -jsf.manageSearch.purge.ObsoletesOccupyDiskSpace=\u904E\u6642\u7684\u9805\u76EE\u4F9D\u7136\u6703\u4F54\u7528\u78C1\u789F\u7A7A\u9593\uFF0C\u4E0D\u904E\u537B\u4E0D\u6703\u56DE\u50B3\u5728\u4EFB\u4F55\u641C\u5C0B\u4E2D\u3002 -jsf.manageSearch.purge.RemoveByRunningOptimize=\u904E\u6642\u7684\u9805\u76EE\u53EF\u85C9\u7531\u5728\u300C\u6E05\u9664\u300D\u5F8C\u57F7\u884C\u300C\u512A\u5316\u300D\u4F86\u5B8C\u5168\u79FB\u9664\u3002 -jsf.manageSearch.reindex=\u91CD\u65B0\u7D22\u5F15 -jsf.manageSearch.reindex.Description=\u5C07\u8868\u683C\u4E2D\u7684\u6240\u6709\u8CC7\u6599\u5217\u5217\u5165\u7D22\u5F15\u3002 -jsf.manageSearch.reindex.OnlyWhenOutOfDate=\u7576\u8CC7\u6599\u88AB\u8A2D\u70BA\u6C38\u7E8C\u6027\u6642\uFF0C\u8CC7\u6599\u5217\u5C07\u6703\u88AB\u81EA\u52D5\u5217\u5165\u7D22\u5F15\uFF0C\u56E0\u6B64\u53EA\u6709\u5728\u7D22\u5F15\u904E\u671F\u6642\uFF08\u6BD4\u65B9\u8AAA\u7576\u91CD\u65B0\u7D22\u5F15\u5931\u6557\uFF0C\u4E26\u4E14\u7D22\u5F15\u6A94\u6848\u88AB\u79FB\u9664\u5F8C\uFF0C\u8CC7\u6599\u5EAB\u85C9\u7531\u5099\u4EFD\u5FA9\u539F\u6642\uFF09\uFF0C\u624D\u9700\u8981\u9032\u884C\u9019\u9805\u4F5C\u696D\u3002 -jsf.manageSearch.reindex.AllRowsWillBeReindexed=\u7D66\u5B9A\u8868\u683C\u7684\u6240\u6709\u8CC7\u6599\u5217\u5C07\u6703\u88AB\u91CD\u65B0\u7D22\u5F15\uFF0C\u7121\u8AD6\u5B83\u5011\u5728\u7D22\u5F15\u4E2D\u662F\u5426\u5DF2\u6709\u9805\u76EE\u3002 -jsf.manageSearch.reindex.IndexedRowsWillBeUpdated=\u5DF2\u5217\u5165\u7D22\u5F15\u7684\u8CC7\u6599\u5217\uFF0C\u5176\u9805\u76EE\u5C07\u6703\u88AB\u66F4\u65B0\uFF0C\u4E26\u4E14\u4E00\u822C\u4E0D\u6703\u5C0D\u9805\u76EE\u9020\u6210\u5F71\u97FF\u3002 -jsf.manageSearch.reindex.TimeAndMemoryWarning=\u8B66\u544A\uFF1A\u56E0\u70BA\u8868\u683C\u6975\u5927\uFF0C\u9019\u9805\u4F5C\u696D\u53EF\u80FD\u6703\u82B1\u4E0A\u6578\u5C0F\u6642\uFF0C\u4E26\u4E14\u5C07\u6703\u4F7F\u7528\u6BD4\u57FA\u6E96\u9084\u8981\u9AD8\u4E0A\u8A31\u591A\u7684\u8A18\u61B6\u9AD4\u3002 -jsf.manageSearch.reindex.RunDuringOffPeak=\u5F37\u70C8\u5EFA\u8B70\u60A8\u5728\u975E\u7E41\u5FD9\uFF0C\u4E26\u4E14\u5E73\u5747\u4F3A\u670D\u5668\u8A18\u61B6\u9AD4\u4F7F\u7528\u91CF\u6700\u4F4E\u7684\u6642\u6BB5\u57F7\u884C\u9019\u9805\u4F5C\u696D\u3002 -jsf.manageSearch.optimize=\u512A\u5316 -jsf.manageSearch.optimize.Description=\u6392\u5217\u7D22\u5F15\u9805\u76EE\u4EE5\u6700\u4F73\u5316\u641C\u5C0B\u901F\u5EA6\u3002 -jsf.manageSearch.optimize.RemovesObsoleteEntries=\u4E26\u4E14\u7531\u7D22\u5F15\u4E2D\u79FB\u9664\u6240\u6709\u5DF2\u904E\u6642\u7684\u9805\u76EE\u3002 -jsf.manageSearch.optimize.WillNotInfluenceIndexTime=\u4E0D\u6703\u5F71\u97FF\u7D22\u5F15\u6642\u9593\u3002 -jsf.manageSearch.optimize.TempFileWarning=\u8B66\u544A\uFF1A\u9019\u9805\u4F5C\u696D\u6703\u4F7F\u7528\u4E00\u500B temp \u6A94\u6848\uFF0C\u4E26\u4E14\u5C07\u6703\u9700\u8981\u8207\u76EE\u524D\u7D22\u5F15\u5927\u5C0F\u5DEE\u4E0D\u591A\u7684\u53EF\u7528\u78C1\u789F\u7A7A\u9593\u3002 -jsf.ManageSearch.SelectNone=\u6E05\u9664\u9078\u9805 -jsf.ManageSearch.PerformSelectedActions=\u9032\u884C\u6240\u9078\u64C7\u7684\u52D5\u4F5C -jsf.ManageSearch.CurrentProgress=\u76EE\u524D\u7684\u9032\u5EA6 -jsf.ManageSearch.NoOperationsRunning=\u6C92\u6709\u57F7\u884C\u4E2D\u7684\u4F5C\u696D -jsf.ManageSearch.Completed=\u5DF2\u6210\u529F\u5B8C\u6210\uFF08\u57F7\u884C\u4E86 \#{reindexAction.elapsedTime}\uFF09 -jsf.ManageSearch.Aborted=\u5DF2\u7531\u4F7F\u7528\u8005\u4E2D\u6B62\uFF08\u57F7\u884C\u4E86 \#{reindexAction.elapsedTime}\uFF09 -jsf.manageSearch.ErrorMessage=\u57FA\u65BC\u4E00\u9805\u932F\u8AA4\uFF0C\u67D0\u4E9B\u7269\u4EF6\u7121\u6CD5\u91CD\u65B0\u7D22\u5F15\u3002\u8ACB\u67E5\u770B\u4F3A\u670D\u5668\u65E5\u8A8C\u4EE5\u53D6\u5F97\u8A73\u7D30\u8CC7\u8A0A\u3002 -jsf.manageSearch.PleaseReindex=\u8ACB\u518D\u6B21\u91CD\u65B0\u7D22\u5F15\uFF0C\u4EE5\u78BA\u4FDD\u641C\u5C0B\u7D22\u5F15\u8655\u65BC\u6700\u65B0\u72C0\u614B\u3002 -jsf.manageSearch.ProgressMessage=\#{reindexAction.reindexCount} \u4E4B \#{reindexAction.reindexProgress} \u9805\u4F5C\u696D\u5DF2\u5B8C\u6210 -jsf.manageSearch.CurrentTable=\u6B63\u5728\u8655\u7406\u8868\u683C\uFF1A\#{reindexAction.currentClass} -jsf.ManageSearch.ElapsedTime=\u57F7\u884C\u4E86\uFF1A\#{reindexAction.elapsedTime} -jsf.ManageSearch.RemainingTime=\u5269\u4E0B\uFF08\u5927\u7D04\uFF09\uFF1A\#{reindexAction.estimatedTimeRemaining} -jsf.ManageSearch.Abort=\u4E2D\u6B62 -# translation auto-copied from project Publican, version 3, document publican, author rlandmann -jsf.Untranslated=\u672A\u7FFB\u8B6F -jsf.rolerules.CreateRule=\u65B0\u898F\u5247 -jsf.rolerules.CreateRoleAssignmentRule=\u5EFA\u7ACB\u89D2\u8272\u5206\u914D\u898F\u5247 -jsf.rolerules.EditRoleAssignmentRule=\u7DE8\u8F2F\u89D2\u8272\u5206\u914D\u898F\u5247 -jsf.rolerules.ConfirmDelete=\u60A8\u662F\u5426\u78BA\u8A8D\u8981\u79FB\u9664\u9019\u9805\u898F\u5247\uFF1F -jsf.rolerules.Description=\u89D2\u8272\u5206\u914D\u898F\u5247\u53EF\u5354\u52A9\u5728\u7279\u5B9A\u4F7F\u7528\u8005\u767B\u5165\u6642\uFF0C\u81EA\u52D5\u5206\u914D\u4F7F\u7528\u8005\u89D2\u8272\u3002\u82E5\u4F7F\u7528\u8005\u7684\u8EAB\u4EFD\uFF08\u4F8B\u5982\u4F7F\u7528\u8005\u540D\u7A31\uFF09\u8207\u7279\u5B9A\u6A21\u5F0F\u76F8\u7B26\uFF0C\u4E26\u4E14\u4EE5\u7279\u5B9A\u65B9\u5F0F\u8A8D\u8B49\uFF08\u6BD4\u65B9\u8AAA\u900F\u904E Open Id\uFF09\u7684\u8A71\uFF0CZanata \u5C07\u80FD\u81EA\u52D5\u70BA\u6B64\u4F7F\u7528\u8005\u6307\u5B9A\u4F7F\u7528\u8005\u89D2\u8272\u3002 -jsf.rolerules.PolicyName=\u653F\u7B56\u540D\u7A31 -jsf.rolerules.PolicyName.tooltip=\u6B64\u4E43\u4F7F\u7528\u8005\u7528\u4F86\u9032\u884C\u8A8D\u8B49\u7684\u8A8D\u8B49\u653F\u7B56\u3002\u82E5\u4E0D\u9078\u64C7\u7684\u8A71\uFF0C\u5B83\u5C07\u6703\u5957\u7528\u81F3\u6240\u6709\u653F\u7B56\u3002 -jsf.rolerules.IdentityPattern=\u8EAB\u4EFD\u6A21\u5F0F -jsf.rolerules.IdentityPattern.tooltip=\u7528\u4F86\u5224\u5B9A\u6B64\u898F\u5247\u662F\u5426\u9069\u7528\u65BC\u7279\u5B9A\u4F7F\u7528\u8005 ID \u7684\u5E38\u898F\u8868\u793A\u5F0F\u3002\u8ACB\u6CE8\u610F\uFF0C\u4F7F\u7528\u8005 ID \u6703\u6839\u64DA\u8A8D\u8B49\u6A5F\u5236\u800C\u6709\u6240\u4E0D\u540C\u3002\u82E5\u9019\u500B\u503C\u88AB\u4FDD\u7559\u70BA\u7A7A\u767D\uFF0C\u898F\u5247\u5C07\u6703\u5957\u7528\u81F3\u300C\u5168\u90E8\u300D\u7684\u4F7F\u7528\u8005 ID\u3002 -jsf.rolerules.RoleToAssign=\u6B32\u5206\u914D\u7684\u89D2\u8272 -jsf.rolerules.RoleToAssign.tooltip=\u6B64\u4E43\u5728\u4F7F\u7528\u8005\u767B\u5165\u6642\uFF0C\u6703\u88AB\u81EA\u52D5\u5206\u914D\u7D66\u4F7F\u7528\u8005\u7684\u89D2\u8272\uFF0C\u524D\u63D0\u662F\u5FC5\u9808\u6EFF\u8DB3\u898F\u5247\u7684\u689D\u4EF6\u3002 -jsf.processmanager.TotalRunning=\u7E3D\u57F7\u884C\u6578\u91CF -jsf.processmanager.TotalFinished=\u7E3D\u5B8C\u6210\u6578\u91CF -# translation auto-copied from project Subscription Manager, version 1.8.X, document keys, author snowlet -jsf.processmanager.Type=\u985E\u578B -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author tchuang -jsf.processmanager.status.Stopped=\u5DF2\u505C\u6B62 -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author snowlet -jsf.processmanager.status.Running=\u57F7\u884C\u4E2D -jsf.processmanager.status.WaitingToStop=\u7B49\u5F85\u505C\u6B62 -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author snowlet -jsf.processmanager.Progress=\u9032\u5EA6 -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author tchuang -jsf.processmanager.StartTime=\u5DF2\u958B\u59CB -# translation auto-copied from project CFSE-cli, version sam-1.2, document keys, author snowlet -jsf.processmanager.FinishTime=\u5DF2\u5B8C\u6210 -# translation auto-copied from project CFSE, version sam-1.2, document app, author snowlet -jsf.processmanager.Duration=\u6301\u7E8C\u6642\u9593 -# translation auto-copied from project aeolus-conductor, version 1.1.1, document defaults, author tchuang -jsf.email.From=\u5BC4\u4EF6\u8005 -jsf.email.ReplyAddress=\u56DE\u8986 -jsf.email.ReplyAddress.description=\uFF08\u60A8\u7684\u96FB\u5B50\u90F5\u4EF6\uFF09 -jsf.email.Subject=\u4E3B\u65E8 -jsf.AdditionalInfo=\u984D\u5916\u8CC7\u8A0A -# translation auto-copied from project CFSE, version sam-1.2, document app, author tchuang -jsf.email.MessageBody=\u8A0A\u606F -jsf.email.Send=\u50B3\u9001\u8A0A\u606F -jsf.NoProjects=\u6C92\u6709\u53EF\u986F\u793A\u7684\u5C08\u6848\u3002 -jsf.SelectProjectVersions=\u9078\u64C7\u5C08\u6848\u7248\u672C -jsf.NoProjectVersionSelected=\u672A\u9078\u64C7\u5C08\u6848\u7248\u672C\u3002 -jsf.ClickSendMessageToProceedRequest=\u8F38\u5165\u984D\u5916\u7684\u8CC7\u8A0A\uFF0C\u4E26\u6309\u4E0B\u300C\u50B3\u9001\u8A0A\u606F\u300D\u4EE5\u7E7C\u7E8C\u9032\u884C -jsf.email.JoinGroupRequest.Subject=\u8ACB\u6C42\u52A0\u5165 '\#{versionGroupJoinAction.groupName}' -jsf.RequestAddProjectToGroup=\u8ACB\u6C42\u52A0\u5165\u7FA4\u7D44 -jsf.AlreadyInGroup=\u5DF2\u5C6C\u65BC\u7FA4\u7D44 -jsf.email.joingrouprequest.AdditionalInfoMessage=\u70BA\u4E86\u78BA\u4FDD\u60A8\u7684\u8ACB\u6C42\u4E0D\u6703\u53D7\u5230\u803D\u64F1\uFF0C\u8ACB\u63D0\u4F9B\u4EFB\u4F55\u53EF\u5354\u52A9\u7FA4\u7D44\u7DAD\u8B77\u8005\uFF0C\u66F4\u5FEB\u901F\u5730\u8655\u7406\u60A8\u8ACB\u6C42\u7684\u984D\u5916\u8CC7\u8A0A\u3002 -jsf.RequestToJoinLanguageTeamTitle=\u8ACB\u6C42\u52A0\u5165 '\#{sendEmail.locale.localeId.id}' \u8A9E\u8A00\u5718\u968A -jsf.email.joinrequest.Subject=\u4F7F\u7528\u8005 '\#{sendEmail.fromLoginName}' \u5E0C\u671B\u52A0\u5165 '\#{sendEmail.locale.localeId.id}' \u8A9E\u8A00\u5718\u968A -jsf.email.ContactCoordinatorTitle=\u806F\u7D61 '\#{sendEmail.locale.retrieveDisplayName()}' \u5354\u8ABF\u54E1 -jsf.contactLanguageTeamCoordinatorForLocale=\u806F\u7D61 '\#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()})' \u8A9E\u8A00\u5718\u968A\u5354\u8ABF\u54E1 -jsf.email.YouAreReceivingThisMailBecause=\u60A8\u6536\u5230\u4E86\u9019\u5C01\u90F5\u4EF6\uFF0C\u56E0\u70BA\uFF1A -jsf.email.GeneratedFromZanataServerAt=\u6B64\u8A0A\u606F\u662F\u7531 Zanata \u6240\u7522\u751F\uFF0C\u57F7\u884C\u65BC\uFF1A -jsf.Account.ActivationMessage=\u60A8\u5F88\u5FEB\u4FBF\u6703\u6536\u5230\u4E00\u5C01\u96FB\u5B50\u90F5\u4EF6\uFF0C\u6B64\u90F5\u4EF6\u5305\u542B\u4E86\u555F\u7528\u60A8\u5E33\u865F\u7684\u9023\u7D50\u3002 -jsf.email.activation.Subject=Zanata \u5E33\u865F\u555F\u7528 -jsf.email.activation.register.DearName=\u89AA\u611B\u7684 \#{emailServiceImpl.toName}\uFF0C -jsf.email.activation.profile.DearName=\u89AA\u611B\u7684 \#{profileAction.name}\uFF0C -jsf.email.activation.ClickLinkToActivateAccount=\u8ACB\u9EDE\u9078\u4E0B\u5217\u9023\u7D50\u4EE5\u555F\u7528\u60A8\u7684\u5E33\u865F\uFF1A -jsf.email.activation.Link=\u5E33\u865F\u555F\u7528\u9023\u7D50 -jsf.email.alternate.copyPasteMessage=\u6B64\u5916\uFF0C\u60A8\u4EA6\u53EF\u5C07\u4E0B\u5217 URL \u526A\u8CBC\u5165\u60A8\u7684\u700F\u89BD\u5668\u4E2D\uFF1A -jsf.UrlExpireMessage=\u6B64\u7DB2\u5740\u5C07\u5728 24 \u5C0F\u6642\u5F8C\u7121\u6548\u3002 -jsf.email.accountchange.Subject=Zanata \u96FB\u5B50\u90F5\u4EF6\u8B8A\u66F4\u78BA\u8A8D -jsf.email.accountchange.DearName=\u89AA\u611B\u7684 \#{profileAction.name}\uFF0C -jsf.email.accountchange.Message=Zanata \u5DF2\u6536\u5230\u8ACB\u6C42\u5C07\u60A8\u7684\u96FB\u5B50\u90F5\u4EF6\u66F4\u65B0\u70BA \#{profileAction.email} -jsf.email.accountchange.Message2=\u82E5\u60A8\u4E26\u672A\u8981\u6C42\u9032\u884C\u6B64\u52D5\u4F5C\uFF0C\u6216\u662F\u4E0D\u78BA\u5B9A\u70BA\u4F55\u6B64\u52D5\u4F5C\u6703\u767C\u751F\uFF0C\u8ACB\u5118\u5FEB\u806F\u7D61 Zanata \u7CFB\u7D71\u7BA1\u7406\u54E1\u3002 -jsf.email.accountchange.ConfirmationLink=\u8ACB\u6309\u6B64\u4EE5\u78BA\u8A8D\u96FB\u5B50\u90F5\u4EF6\u8B8A\u66F4 -jsf.email.usernamechange.Subject=\u60A8\u7684 Zanata \u4F7F\u7528\u8005\u540D\u7A31\u5DF2\u66F4\u6539\u3002 -jsf.email.usernamechange.DearName=\u89AA\u611B\u7684 \#{userAction.getName(userAction.username)}\uFF0C -jsf.email.usernamechange.Content=\u60A8\u7684 Zanata \u4F7F\u7528\u8005\u540D\u7A31\u6700\u8FD1\u5DF2\u7D93\u7531\u5176\u4E2D\u4E00\u4F4D\u7CFB\u7D71\u7BA1\u7406\u54E1\u66F4\u6539\u3002\u82E5\u60A8\u4E26\u672A\u8981\u6C42\u9032\u884C\u9019\u9805\u52D5\u4F5C\uFF0C\u6216\u662F\u4E0D\u78BA\u5B9A\u6B64\u52D5\u4F5C\u70BA\u4F55\u6703\u767C\u751F\uFF0C\u8ACB\u5118\u5FEB\u806F\u7D61 Zanata \u7CFB\u7D71\u7BA1\u7406\u54E1\u3002 -jsf.email.usernamechange.YourNewUsername=\u60A8\u7684\u65B0\u4F7F\u7528\u8005\u540D\u7A31\u70BA '\#{userAction.username}' -jsf.email.usernamechange.ResetPassword=\u60A8\u9700\u8981\u91CD\u8A2D\u60A8\u7684\u5BC6\u78BC\u3002\u82E5\u8981\u9019\u9EBC\u505A\uFF0C\u8ACB\u9EDE\u9078\u4EE5\u4E0B\u9023\u7D50\uFF1A -jsf.email.usernamechange.ClickLinkForPasswordReset=\u8ACB\u6309\u6B64\u91CD\u8A2D\u60A8\u7684\u5BC6\u78BC -jsf.email.passwordreset.Subject=Zanata \u91CD\u8A2D\u5BC6\u78BC\u8ACB\u6C42 -jsf.email.passwordreset.DearName=\u89AA\u611B\u7684 \#{passwordResetRequest.account.person.name}\uFF0C -jsf.email.passwordreset.FollowLinkToResetPassword=\u8ACB\u7D93\u7531\u4EE5\u4E0B\u9023\u7D50\uFF0C\u91CD\u8A2D\u60A8\u5E33\u865F\u7684\u5BC6\u78BC\u3002 -jsf.email.passwordreset.IgnoreIfNotRequested=\u82E5\u60A8\u4E26\u672A\u660E\u78BA\u8981\u6C42\u91CD\u8A2D\u5BC6\u78BC\uFF0C\u60A8\u53EF\u5FFD\u7565\u9019\u9805\u8ACB\u6C42\u3002 -jsf.email.admin.SentNotification=\u60A8\u7684\u8A0A\u606F\u5DF2\u50B3\u9001\u7D66\u7BA1\u7406\u54E1 -jsf.email.admin.SubjectPrefix=\u4F86\u81EA\u65BC '\#{sendEmail.fromLoginName}' \u7684 Zanata \u4F7F\u7528\u8005\u96FB\u5B50\u90F5\u4EF6\uFF1A -jsf.ZanataAdministrator=Zanata \u7BA1\u7406\u54E1 -jsf.email.admin.DearAdmin=\u89AA\u611B\u7684\u7BA1\u7406\u54E1\uFF0C -jsf.email.admin.UserMessageIntro=Zanata \u4F7F\u7528\u8005 '\#{sendEmail.fromName}'\uFF0CId '\#{sendEmail.fromLoginName}' \u5DF2\u50B3\u9001\u4E86\u4E0B\u5217\u8A0A\u606F\uFF1A -jsf.email.ReplyInstructions=\u60A8\u53EF\u85C9\u7531 \#{sendEmail.replyEmail} \u56DE\u8986 \#{sendEmail.fromName} -jsf.email.admin.ReceivedReason=\u60A8\u4E43\u7CFB\u7D71\u914D\u7F6E\u4E2D\u7684\u7BA1\u7406\u54E1 -jsf.email.admin.user.ReceivedReason=\u60A8\u662F\u4E00\u4F4D\u7BA1\u7406\u54E1 -jsf.email.coordinator.SentNotification=\u60A8\u7684\u8A0A\u606F\u5DF2\u50B3\u9001\u7D66 \#{sendEmail.locale.retrieveNativeName()} \u8A9E\u8A00\u5718\u968A -jsf.email.coordinator.SubjectPrefix=Zanata\uFF1A\#{sendEmail.locale.localeId.id} \u8A9E\u8A00\u5718\u968A\uFF1A\u4F86\u81EA\u65BC '\#{sendEmail.fromLoginName}' \u7684\u8A0A\u606F\uFF1A -jsf.email.coordinator.DearCoordinator=\u89AA\u611B\u7684\u8A9E\u8A00\u5718\u968A\u5354\u8ABF\u54E1 -jsf.email.coordinator.UserMessageIntro=Zanata \u4F7F\u7528\u8005 '\#{sendEmail.fromName}'\uFF0Cid '\#{sendEmail.fromLoginName}' \u5DF2\u50B3\u9001\u4E0B\u5217\u8A0A\u606F\u81F3 \#{sendEmail.locale.localeId.id} (\#{sendEmail.locale.retrieveNativeName()}) \u8A9E\u8A00\u5718\u968A\uFF1A -jsf.email.coordinator.ResponseInstructions=\u60A8\u53EF\u9EDE\u9078\u4EE5\u4E0B\u7684\u9023\u7D50\uFF0C\u4EE5\u76F4\u63A5\u524D\u5F80 \#{sendEmail.locale.localeId.id} \u8A9E\u8A00\u5718\u968A\u7DB2\u9801\u3002\u7576\u8655\u7406\u5B8C\u4E86\u8ACB\u6C42\u5F8C\uFF0C\u8ACB\u65BC \#{sendEmail.replyEmail} \u56DE\u8986 \#{sendEmail.fromName}\u3002 -jsf.email.coordinator.ReceivedReason=\u60A8\u662F '\#{sendEmail.locale.retrieveNativeName()}' \u8A9E\u8A00\u5718\u968A\u7684\u5354\u8ABF\u54E1 -jsf.email.group.maintainer.SentNotification=\u60A8\u7684\u8A0A\u606F\u5DF2\u50B3\u9001\u7D66 \#{versionGroupJoinAction.groupName} \u7FA4\u7D44\u7684\u7DAD\u8B77\u8005 -jsf.email.maintainer.DearMaintainer=\u89AA\u611B\u7684\u7FA4\u7D44\u7DAD\u8B77\u8005\uFF0C -jsf.email.joingrouprequest.RequestingToJoinGroup=Zanata \u4F7F\u7528\u8005 '\#{sendEmail.fromName}'\uFF0CId '\#{sendEmail.fromLoginName}' \u8981\u6C42\u5C07\u4ED6/\u5979\u7684\u5C08\u6848\u52A0\u5165 '\#{versionGroupJoinAction.groupName}' \u7FA4\u7D44\u4E2D\u3002 -jsf.email.JoinGroupRequest.ResponseInstructions=\u8ACB\u9EDE\u9078\u4EE5\u4E0B\u9023\u7D50\u4EE5\u8655\u7406\u8ACB\u6C42\u3002\u7576\u60A8\u5B8C\u6210\u8655\u7406\u8ACB\u6C42\u5F8C\uFF0C\u65BC \#{sendEmail.replyEmail} \u56DE\u8986 \#{sendEmail.fromName}\u3002 -jsf.email.group.maintainer.ReceivedReason=\u60A8\u662F '\#{versionGroupJoinAction.groupName}' \u7FA4\u7D44\u7684\u7DAD\u8B77\u8005 -up=\u2191 -down=\u2193 -left=\u2039 -right=\u203A -org.jboss.seam.loginFailed=\u767B\u5165\u5931\u6557 -org.jboss.seam.loginSuccessful=\u6B61\u8FCE\u60A8 \#0\! -org.jboss.seam.NotLoggedIn=\u8ACB\u5148\u767B\u5165 -org.jboss.seam.TransactionFailed=\u4EA4\u6613\u5931\u6557 -org.jboss.seam.NoConversation=\u4EA4\u8AC7\u5DF2\u7D50\u675F\u3001\u903E\u6642\u6216\u6B63\u5728\u8655\u7406\u5176\u5B83\u8ACB\u6C42 -org.jboss.seam.IllegalNavigation=\u700F\u89BD\u9055\u53CD\u898F\u5247 -org.jboss.seam.ProcessEnded=\u7A0B\u5E8F \#0 \u5DF2\u7D50\u675F -org.jboss.seam.ProcessNotFound=\u627E\u4E0D\u5230\u7A0B\u5E8F \#0 -org.jboss.seam.TaskEnded=\u4EFB\u52D9 \#0 \u5DF2\u7D50\u675F -org.jboss.seam.TaskNotFound=\u627E\u4E0D\u5230\u4EFB\u52D9 \#0 -javax.faces.component.UIInput.CONVERSION=\u503C\u7121\u6CD5\u8F49\u63DB\u70BA\u9810\u671F\u7684\u985E\u578B -javax.faces.component.UIInput.REQUIRED=\u9700\u63D0\u4F9B\u6709\u6548\u7684\u503C -javax.faces.component.UIInput.UPDATE=\u8655\u7406\u60A8\u63D0\u4EA4\u7684\u8CC7\u8A0A\u6642\u767C\u751F\u4E86\u932F\u8AA4 -javax.faces.component.UISelectOne.INVALID=\u63D0\u4F9B\u7684\u503C\u7121\u6548 -javax.faces.component.UISelectMany.INVALID=\u63D0\u4F9B\u7684\u503C\u7121\u6548 -javax.faces.converter.BigDecimalConverter.DECIMAL=\u503C\u5FC5\u9808\u662F\u500B\u6578\u5B57 -javax.faces.converter.BigDecimalConverter.DECIMAL_detail=\u503C\u5FC5\u9808\u662F\u500B\u5DF2\u7C3D\u7F72\u7684\u5C0F\u6578\u9EDE\u6578\u5B57\uFF0C\u5305\u542B\u4E86\u96F6\u6216\u66F4\u591A\u500B\u6578\u5B57\uFF0C\u4E26\u4E14\u53EF\u9078\u7528\u6027\u5305\u542B\u4E00\u500B\u5C0F\u6578\u9EDE\u6216\u662F\u5206\u6578\uFF0C\u4F8B\u5982 {1} -javax.faces.converter.BigIntegerConverter.BIGINTEGER=\u503C\u5FC5\u9808\u662F\u500B\u6574\u6578 -javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail=\u503C\u5FC5\u9808\u662F\u500B\u5DF2\u7C3D\u7F72\u7684\u6574\u6578\u503C\uFF0C\u5305\u542B\u96F6\u6216\u66F4\u591A\u500B\u6578\u5B57 -javax.faces.converter.BooleanConverter.BOOLEAN=\u503C\u5FC5\u9808\u662F true \u6216 false -javax.faces.converter.BooleanConverter.BOOLEAN_detail=\u503C\u5FC5\u9808\u662F true \u6216 false\uFF08\u4EFB\u4F55\u975E true \u7684\u503C\u7686\u6703\u88AB\u8A55\u4F30\u70BA false\uFF09 -javax.faces.converter.ByteConverter.BYTE=\u503C\u5FC5\u9808\u662F\u500B\u4ECB\u65BC 0 \u8207 255 \u4E4B\u9593\u7684\u6578\u5B57 -javax.faces.converter.ByteConverter.BYTE_detail=\u503C\u5FC5\u9808\u662F\u500B\u4ECB\u65BC 0 \u8207 255 \u4E4B\u9593\u7684\u6578\u5B57 -javax.faces.converter.CharacterConverter.CHARACTER=\u503C\u5FC5\u9808\u662F\u500B\u5B57\u5143 -javax.faces.converter.CharacterConverter.CHARACTER_detail=\u503C\u5FC5\u9808\u662F\u500B\u6709\u6548\u7684 ASCII \u5B57\u5143 -javax.faces.converter.DateTimeConverter.DATE=\u503C\u5FC5\u9808\u662F\u500B\u65E5\u671F -javax.faces.converter.DateTimeConverter.DATE_detail=\u503C\u5FC5\u9808\u662F\u500B\u65E5\u671F\uFF0C\u4F8B\u5982 {1} -javax.faces.converter.DateTimeConverter.TIME=\u503C\u5FC5\u9808\u662F\u4E00\u6BB5\u6642\u9593 -javax.faces.converter.DateTimeConverter.TIME_detail=\u503C\u5FC5\u9808\u662F\u4E00\u6BB5\u6642\u9593\uFF0C\u4F8B\u5982 {1} -javax.faces.converter.DateTimeConverter.DATETIME=\u503C\u5FC5\u9808\u662F\u65E5\u671F\u8207\u6642\u9593 -javax.faces.converter.DateTimeConverter.DATETIME_detail=\u503C\u5FC5\u9808\u662F\u65E5\u671F\u8207\u6642\u9593\uFF0C\u4F8B\u5982 {1} -javax.faces.converter.DateTimeConverter.PATTERN_TYPE=\u82E5\u8981\u5C07\u503C\u8F49\u63DB\uFF0C\u60A8\u5FC5\u9808\u6307\u5B9A\u4E00\u500B\u6A21\u5F0F\u6216\u985E\u578B -javax.faces.converter.DoubleConverter.DOUBLE=\u503C\u5FC5\u9808\u662F\u500B\u6578\u5B57 -javax.faces.converter.DoubleConverter.DOUBLE_detail=\u503C\u5FC5\u9808\u662F\u500B\u4ECB\u65BC 4.9E-324 \u548C 1.7976931348623157E308 \u4E4B\u9593\u7684\u6578\u5B57 -javax.faces.converter.EnumConverter.ENUM=\u503C\u5FC5\u9808\u8981\u80FD\u5920\u8F49\u63DB\u70BA\u4E00\u7D44 enum -javax.faces.converter.EnumConverter.ENUM_detail=\u503C\u5FC5\u9808\u8981\u80FD\u5920\u8F49\u63DB\u70BA\u4E00\u7D44 enum\uFF0C\u6216\u662F\u7531\u5305\u542B\u5E38\u6578 {1} \u7684 enum \u8F49\u63DB -javax.faces.converter.EnumConverter.ENUM_NO_CLASS=\u503C\u5FC5\u9808\u8981\u80FD\u5920\u8F49\u63DB\u70BA\u4E00\u7D44 enum \u6216\u662F\u7531 enum \u8F49\u63DB\uFF0C\u4E0D\u904E\u4E0D\u63D0\u4F9B enum class -javax.faces.converter.EnumConverter.ENUM_NO_CLASS_detail=\u503C\u5FC5\u9808\u8981\u80FD\u5920\u8F49\u63DB\u70BA\u4E00\u7D44 enum \u6216\u662F\u7531 enum \u8F49\u63DB\uFF0C\u4E0D\u904E\u4E0D\u63D0\u4F9B enum class -javax.faces.converter.FloatConverter.FLOAT=\u503C\u5FC5\u9808\u662F\u500B\u6578\u5B57 -javax.faces.converter.FloatConverter.FLOAT_detail=\u503C\u5FC5\u9808\u662F\u500B\u4ECB\u65BC 1.4E-45 \u548C 3.4028235E38 \u4E4B\u9593\u7684\u6578\u5B57 -javax.faces.converter.IntegerConverter.INTEGER=\u503C\u5FC5\u9808\u662F\u500B\u6574\u6578 -javax.faces.converter.IntegerConverter.INTEGER_detail=\u503C\u5FC5\u9808\u662F\u500B\u4ECB\u65BC -2147483648 \u548C 2147483647 \u4E4B\u9593\u7684\u6574\u6578 -javax.faces.converter.LongConverter.LONG=\u503C\u5FC5\u9808\u662F\u500B\u6574\u6578 -javax.faces.converter.LongConverter.LONG_detail=\u503C\u5FC5\u9808\u662F\u500B\u4ECB\u65BC -9223372036854775808 \u548C 9223372036854775807 \u4E4B\u9593\u7684\u6574\u6578\u503C -javax.faces.converter.NumberConverter.CURRENCY=\u503C\u5FC5\u9808\u662F\u8CA8\u5E63\u6578\u91CF -javax.faces.converter.NumberConverter.CURRENCY_detail=\u503C\u5FC5\u9808\u662F\u8CA8\u5E63\u6578\u91CF\uFF0C\u4F8B\u5982 {1} -javax.faces.converter.NumberConverter.PERCENT=\u503C\u5FC5\u9808\u662F\u500B\u767E\u5206\u6BD4\u6578\u91CF -javax.faces.converter.NumberConverter.PERCENT_detail=\u503C\u5FC5\u9808\u662F\u500B\u767E\u5206\u6BD4\u6578\u91CF\uFF0C\u4F8B\u5982 {1} -javax.faces.converter.NumberConverter.NUMBER=\u503C\u5FC5\u9808\u662F\u500B\u6578\u5B57 -javax.faces.converter.NumberConverter.NUMBER_detail=\u503C\u5FC5\u9808\u662F\u500B\u6578\u5B57 -javax.faces.converter.NumberConverter.PATTERN=\u503C\u5FC5\u9808\u662F\u500B\u6578\u5B57 -javax.faces.converter.NumberConverter.PATTERN_detail=\u503C\u5FC5\u9808\u662F\u500B\u6578\u5B57 -javax.faces.converter.ShortConverter.SHORT=\u503C\u5FC5\u9808\u662F\u500B\u6574\u6578 -javax.faces.converter.ShortConverter.SHORT_detail=\u503C\u5FC5\u9808\u662F\u500B\u4ECB\u65BC -32768 \u548C 32767 \u4E4B\u9593\u7684\u6574\u6578 -javax.faces.validator.DoubleRangeValidator.MAXIMUM=\u503C\u5FC5\u9808\u5C0F\u65BC\u6216\u7B49\u65BC {0} -javax.faces.validator.DoubleRangeValidator.MINIMUM=\u503C\u5FC5\u9808\u5927\u65BC\u6216\u7B49\u65BC {0} -javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE=\u503C\u5FC5\u9808\u4ECB\u65BC {0} \u548C {1} \u4E4B\u9593 -javax.faces.validator.DoubleRangeValidator.TYPE=\u503C\u7684\u985E\u578B\u4E0D\u6B63\u78BA -javax.faces.validator.LengthValidator.MAXIMUM=\u503C\u7684\u9577\u5EA6\u5FC5\u9808\u5C0F\u65BC\u6216\u5927\u65BC {0} \u500B\u5B57\u5143 -javax.faces.validator.LengthValidator.MINIMUM=\u503C\u7684\u9577\u5EA6\u5FC5\u9808\u5927\u65BC\u6216\u7B49\u65BC {0} \u500B\u5B57\u5143 -javax.faces.validator.LongRangeValidator.MAXIMUM=\u503C\u5FC5\u9808\u5C0F\u65BC\u6216\u7B49\u65BC {0} -javax.faces.validator.LongRangeValidator.MINIMUM=\u503C\u5FC5\u9808\u5927\u65BC\u6216\u7B49\u65BC {0} -javax.faces.validator.LongRangeValidator.NOT_IN_RANGE=\u503C\u5FC5\u9808\u4ECB\u65BC {0} \u548C {1} \u4E4B\u9593 -javax.faces.validator.LongRangeValidator.TYPE=\u503C\u7684\u985E\u578B\u4E0D\u6B63\u78BA -javax.faces.validator.NOT_IN_RANGE=\u503C\u5FC5\u9808\u4ECB\u65BC {0} \u548C {1} \u4E4B\u9593 -javax.faces.converter.STRING=\u503C\u7121\u6CD5\u8F49\u63DB\u6210\u5B57\u4E32 diff --git a/zanata-war/src/main/resources/org/zanata/adapter/SubtitleAdapterDefaultConfiguration.yml b/zanata-war/src/main/resources/org/zanata/adapter/SubtitleAdapterDefaultConfiguration.yml new file mode 100644 index 0000000000..91f097f98a --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/adapter/SubtitleAdapterDefaultConfiguration.yml @@ -0,0 +1,24 @@ +useLD.b=true +localizeOutside.b=true +startString=" +endString=" +extractOuterStrings.b=false +useBSlashEscape.b=true +oneLevelGroups.b=false +regexOptions.i=40 +mimeType=text/plain +ruleCount.i=1 +rule0.ruleName=Rule +rule0.ruleType.i=1 +rule0.expr=^(\d\d:\d\d:\d\d.*?|\d\d:\d\d\.\d\d\d.*?)\n(.*?)(\n\n|\z) +rule0.groupSource.i=2 +rule0.groupTarget.i=-1 +rule0.groupName.i=1 +rule0.groupNote.i=-1 +rule0.preserveWS.b=true +rule0.useCodeFinder.b=true +rule0.sample=1$0a$00:00:20,000 --> 00:00:24,400 X1:100 X2:600 Y1:050 Y2:100$0a$text line 1$0a$line 2$0a$$0a$2$0a$00:00:24,600 --> 00:00:27,800$0a$Text entry 2$0a$ +rule0.codeFinderRules.count.i=1 +rule0.codeFinderRules.rule0=<\w+.*?>| +rule0.codeFinderRules.sample=test bold, test +rule0.codeFinderRules.useAllRulesWhenTesting.b=false diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/activation.vm b/zanata-war/src/main/resources/org/zanata/email/templates/activation.vm new file mode 100644 index 0000000000..fdf8476aaf --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/activation.vm @@ -0,0 +1,25 @@ +

$msgs.format("jsf.email.activation.register.DearName", $toName)

+ +

$msgs.get("jsf.email.activation.ClickLinkToActivateAccount")

+ +

+ + $msgs.get("jsf.email.activation.Link") + +

+ +

+ $msgs.get("jsf.email.alternate.copyPasteMessage") +

+ +

+ + $serverPath/account/activate/$activationKey + +

+ +

+ $msgs.get("jsf.UrlExpireMessage") +

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/email_admin.vm b/zanata-war/src/main/resources/org/zanata/email/templates/email_admin.vm new file mode 100644 index 0000000000..5bd3e2f468 --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/email_admin.vm @@ -0,0 +1,7 @@ +

$msgs.get("jsf.email.admin.DearAdmin")

+ +

$msgs.format("jsf.email.admin.UserMessageIntro", $fromName, $fromLoginName)

+
+$htmlMessage +
+

$msgs.format("jsf.email.ReplyInstructions", $fromName, $replyEmail)

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/email_coordinator.vm b/zanata-war/src/main/resources/org/zanata/email/templates/email_coordinator.vm new file mode 100644 index 0000000000..a65d51504f --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/email_coordinator.vm @@ -0,0 +1,14 @@ +

$msgs.get("jsf.email.coordinator.DearCoordinator")

+

$msgs.format("jsf.email.coordinator.UserMessageIntro", + $fromName, $fromLoginName, $localeId, $localeNativeName)

+
+$htmlMessage +
+

$msgs.format("jsf.email.coordinator.ResponseInstructions", + $localeId, $fromName, $replyEmail)

+

+ + $serverPath/language/view/$localeId + +

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/email_request_role_language.vm b/zanata-war/src/main/resources/org/zanata/email/templates/email_request_role_language.vm new file mode 100644 index 0000000000..0ca61158c8 --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/email_request_role_language.vm @@ -0,0 +1,46 @@ +

$msgs.get("jsf.email.coordinator.DearCoordinator")

+ +

+ $msgs.format("jsf.email.rolerequest.UserRequestingRole", + $fromName, $fromLoginName, $localeId, $localeNativeName) +

    + + ## NB comparing against true allows us to detect missing context variables + #if ($requestAsTranslator == true) +
  • + $msgs.get("jsf.Translator") +
  • + #end + + #if ($requestAsReviewer == true) +
  • + $msgs.get("jsf.Reviewer") +
  • + #end + + #if ($requestAsCoordinator == true) +
  • + $msgs.get("jsf.Coordinator") +
  • + #end +
+

+ +#if ($htmlMessage) +

$msgs.format("jsf.email.UserMessageIntro", $fromName)

+
+ $htmlMessage +
+#end + +

$msgs.format("jsf.email.rolerequest.AddUserInstructions", $fromName, $localeId)

+ +

$msgs.format("jsf.email.coordinator.ResponseInstructions", + $localeId, $fromName, $replyEmail)

+ +

+ + $serverPath/language/view/$localeId + +

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/email_request_to_join_group.vm b/zanata-war/src/main/resources/org/zanata/email/templates/email_request_to_join_group.vm new file mode 100644 index 0000000000..4e659768f3 --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/email_request_to_join_group.vm @@ -0,0 +1,29 @@ +

$msgs.get("jsf.email.maintainer.DearMaintainer")

+ +

$msgs.format("jsf.email.joingrouprequest.RequestingToJoinGroup", + $fromName, $fromLoginName, $groupName)

+ +
    + #foreach($projIterId in $projectIterationIds) +
  • + $msgs.get("jsf.Project"):$projIterId.projectSlug - $msgs.get("jsf.Version"):$projIterId.iterationSlug +
  • + #end +
+ +#if ($htmlMessage) +

$msgs.format("jsf.email.UserMessageIntro", $fromName)

+
+$htmlMessage +
+#end + +

$msgs.format("jsf.email.JoinGroupRequest.ResponseInstructions", + $fromName, $replyEmail)

+ +

+ + $serverPath/version-group/view/$versionGroupSlug#settings-projects + +

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/email_request_to_join_language.vm b/zanata-war/src/main/resources/org/zanata/email/templates/email_request_to_join_language.vm new file mode 100644 index 0000000000..604abb1dee --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/email_request_to_join_language.vm @@ -0,0 +1,50 @@ +

$msgs.get("jsf.email.coordinator.DearCoordinator")

+ +

+ $msgs.format("jsf.email.joinrequest.UserRequestingToJoin", + $fromName, $fromLoginName, $localeId, $localeNativeName) + #if ($requestAsTranslator || $requestAsReviewer || $requestAsCoordinator) +
+ $msgs.format("jsf.email.joinrequest.RoleRequested") +

    + ## NB comparing against true allows us to detect missing context variables + #if ($requestAsTranslator == true) +
  • + $msgs.get("jsf.Translator") +
  • + #end + + #if ($requestAsReviewer == true) +
  • + $msgs.get("jsf.Reviewer") +
  • + #end + + #if ($requestAsCoordinator == true) +
  • + $msgs.get("jsf.Coordinator") +
  • + #end +
+ #end +

+ +#if ($htmlMessage) +

$msgs.format("jsf.email.UserMessageIntro", $fromName)

+
+ $htmlMessage +
+#end + +

$msgs.format("jsf.email.joinrequest.AddUserInstructions", + $fromName, $localeId, $msgs.get("jsf.AddTeamMember"), $fromLoginName)

+ +

$msgs.format("jsf.email.coordinator.ResponseInstructions", + $localeId, $fromName, $replyEmail)

+ +

+ + $serverPath/language/view/$localeId + +

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/email_validation.vm b/zanata-war/src/main/resources/org/zanata/email/templates/email_validation.vm new file mode 100644 index 0000000000..b4894da71a --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/email_validation.vm @@ -0,0 +1,26 @@ +

$msgs.format("jsf.email.accountchange.DearName", $toName)

+ +

$msgs.format("jsf.email.accountchange.Message", $newEmail) +
$msgs.get("jsf.email.accountchange.Message2")

+ +

+ + $msgs.get("jsf.email.accountchange.ConfirmationLink") + +

+ +

+ $msgs.get("jsf.email.alternate.copyPasteMessage") +

+ +

+ $msgs.get("jsf.UrlExpireMessage") +

+ +

+ + $serverPath/account/validate_email/$activationKey + +

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/password_reset.vm b/zanata-war/src/main/resources/org/zanata/email/templates/password_reset.vm new file mode 100644 index 0000000000..243b86e01c --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/password_reset.vm @@ -0,0 +1,12 @@ +

$msgs.format("jsf.email.passwordreset.DearName", $toName)

+ +

$msgs.get("jsf.email.passwordreset.FollowLinkToResetPassword")

+ +

$msgs.get("jsf.email.passwordreset.IgnoreIfNotRequested")

+ +

+ + $serverPath/account/password_reset/$activationKey + +

diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/template_email.vm b/zanata-war/src/main/resources/org/zanata/email/templates/template_email.vm new file mode 100644 index 0000000000..81541f96b5 --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/template_email.vm @@ -0,0 +1,23 @@ + + + + + +#parse($body) +
+ #if ($receivedReason) +

+ + $msgs.get("jsf.email.YouAreReceivingThisMailBecause")
+ $receivedReason
+
+

+ #end +

+ $msgs.get("jsf.email.GeneratedFromZanataServerAt") + + $serverPath + +

+ + diff --git a/zanata-war/src/main/resources/org/zanata/email/templates/username_changed.vm b/zanata-war/src/main/resources/org/zanata/email/templates/username_changed.vm new file mode 100644 index 0000000000..204c774450 --- /dev/null +++ b/zanata-war/src/main/resources/org/zanata/email/templates/username_changed.vm @@ -0,0 +1,16 @@ +

$msgs.format("jsf.email.usernamechange.DearName", $toName)

+ +

$msgs.get("jsf.email.usernamechange.Content")

+ +

$msgs.format("jsf.email.usernamechange.YourNewUsername", $newUsername)

+ +#if ($shouldResetPassword) +

$msgs.get("jsf.email.usernamechange.ResetPassword")

+ +

+ + $msgs.get("jsf.email.usernamechange.ClickLinkForPasswordReset") + +

+#end diff --git a/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml b/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml index a7442b6a12..25eee39c08 100644 --- a/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml +++ b/zanata-war/src/main/resources/org/zanata/webtrans/public/Application.xhtml @@ -12,7 +12,7 @@ - #{messages['jsf.PageTitle']} + #{msgs['jsf.PageTitle']} diff --git a/zanata-war/src/main/resources/security.drl b/zanata-war/src/main/resources/security.drl deleted file mode 100644 index 7918c02109..0000000000 --- a/zanata-war/src/main/resources/security.drl +++ /dev/null @@ -1,539 +0,0 @@ -package ZanataPermissions; - -import java.security.Principal; - -import org.zanata.model.HAccount; -import org.zanata.model.HLocale; -import org.zanata.model.HLocaleMember; -import org.zanata.model.HPerson; -import org.zanata.model.HProject; -import org.zanata.model.HProjectIteration; -import org.zanata.model.HIterationGroup; - -import org.jboss.seam.security.Identity; -import org.jboss.seam.security.Role; -import org.jboss.seam.security.permission.PermissionCheck; -import org.jboss.seam.security.permission.RoleCheck; - -import function org.zanata.security.SecurityFunctions.isUserAllowedAccess; -import function org.zanata.security.SecurityFunctions.isUserTranslatorOfLanguage; -import function org.zanata.security.SecurityFunctions.isUserReviewerOfLanguage; -import function org.zanata.security.SecurityFunctions.isUserCoordinatorOfLanguage; -import function org.zanata.security.SecurityFunctions.isLanguageTeamMember; - -/* admin can do anything */ -rule AdminAnything - no-loop - activation-group "permissions" -when - check: PermissionCheck(granted == false) - Role(name == "admin") -then - check.grant(); -end - -rule CreateAccount - no-loop - activation-group "permissions" -when - check: PermissionCheck(target == "seam.account", action == "create", granted == false) - Role(name == "admin") -then - check.grant(); -end - -/***************************************************************************************** - - The Following Rules are for Identity Management - -******************************************************************************************/ - -rule ManageUsers - no-loop - activation-group "permissions" -when - check: PermissionCheck(target == "seam.user", granted == false) - Role(name == "admin") -then - check.grant(); -end - -rule ManageRoles - no-loop - activation-group "permissions" -when - check: PermissionCheck(target == "seam.role", granted == false) - Role(name == "admin") -then - check.grant(); -end - - -/***************************************************************************************** - - Project ownership rules - -******************************************************************************************/ - -/* admin can delete projects (see rule AdminAnything above) */ - -/* Any authenticated user can create a project */ -rule CreateProject - no-loop - activation-group "permissions" -when - $project: HProject() - $authenticatedPerson: HPerson() - check: PermissionCheck(target == $project, action == "insert", granted == false ) -then - check.grant(); -end - -/* anyone can read a project */ -rule ReadProject - no-loop - activation-group "permissions" -when - $project: HProject() - check: PermissionCheck(target == $project, action == "read", granted == false) -then - check.grant(); -end - - -/* anyone can read a project iteration */ -rule ReadProjectIteration - no-loop - activation-group "permissions" -when - $iter: HProjectIteration() - check: PermissionCheck(target == $iter, action == "read", granted == false) -then - check.grant(); -end - - -/* - Project maintainers may edit (but not delete) a project, or add an iteration. - Note that 'add-iteration' (on a project) should be granted in the same - circumstances that 'insert' is granted (on an iteration). In other words, - make sure the rules agree with each other. (NB: 'add-iteration' is used in the - UI to enable buttons etc, without requiring the construction of - HProjectIteration just to do a permission check.) - */ -rule UpdateProjectOrAddIteration - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "update" || action == "add-iteration", granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $project: HProject() - HPerson( id == authenticatedPerson.id ) from $project.maintainers -then - check.grant(); -end - - -/* - Project maintainers may create or edit (but not delete) a project iteration - */ -rule InsertOrUpdateProjectIteration - no-loop - activation-group "permissions" -when - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $iter: HProjectIteration( - $project : project, authenticatedPerson.isMaintainer($project) - ) - check: PermissionCheck( - target == $iter, - action == "insert" || action == "update" || action == "import-template", - granted == false) -then - check.grant(); -end - - -/* - This rule grants 'insert' on iteration if 'add-iteration' is granted - on the project. It works, but it seems like a bad idea to re-invoke - the rules framework recursively like this. Instead, just make sure the rules - above agree with each other! - */ -/* -rule GrantInsertIfAddIterationGranted - no-loop - activation-group "permissions" -when - $iter: HProjectIteration() - check: PermissionCheck(target == $iter, action == "insert", granted == false) - eval(Identity.instance().hasPermission($iter.getProject(), "add-iteration")) -then - check.grant(); -end -*/ - - -/***************************************************************************************** - - Translation rules - -******************************************************************************************/ - -/* Language Team members can add a translation for their language teams */ - -rule LangTeamMemberAddTranslation - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "add-translation" || action == "modify-translation", granted == false) - authenticatedPerson: HPerson() - $project: HProject( eval(isUserAllowedAccess($project)) ) - eval(authenticatedPerson != null) - $locale: HLocale( - eval(isUserTranslatorOfLanguage($locale)) - ) -then - check.grant(); -end - -/* Language Team reviewer can approve/reject translation */ - -rule LangTeamReviewerReviewTranslation - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "review-translation", granted == false) - authenticatedPerson: HPerson() - $project: HProject( eval(isUserAllowedAccess($project)) ) - eval(authenticatedPerson != null) - $locale: HLocale( - eval(isUserReviewerOfLanguage($locale)) - ) -then - check.grant(); -end - -/* Project Maintainers can add a translation for their projects */ - -rule ProjectMaintainerAddTranslation - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "add-translation" || action == "modify-translation" || action == "review-translation", granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $project: HProject( - eval(authenticatedPerson.isMaintainer($project)) - ) -then - check.grant(); -end - -/* Project Maintainer can import translation (merge type is IMPORT) */ -rule ProjectMaintainerImportTranslation - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "import-translation", granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $iteration: HProjectIteration( - eval( authenticatedPerson.isMaintainer( $iteration.getProject() ) ) - ) -then - check.grant(); -end - -/***************************************************************************************** - - Glossary rules - -******************************************************************************************/ - -/* 'glossarist' can push */ -rule GlossaristPushGlossary - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "glossary-insert" || action == "glossary-update", granted == false) - Role(name == "glossarist") -then - check.grant(); -end - -/* 'glossarist-admin' can delete */ -rule GlossaristDeleteGlossary - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "glossary-delete" || action == "glossary-update" || action == "glossary-insert", granted == false) - Role(name == "glossary-admin") -then - check.grant(); -end - - -/***************************************************************************************** - - Language Team Coordinator rules - -******************************************************************************************/ - -/* Anyone can read Locale members */ - -rule ReadLocaleMembers - no-loop - activation-group "permissions" -when - $member: HLocaleMember() - check: PermissionCheck(target == $member, action == "read", granted == false) -then - check.grant(); -end - - -/* 'team coordinator' can manage language teams */ - -rule TeamCoordinatorManageLanguageTeam - no-loop - activation-group "permissions" -when - PermissionCheck(action == "manage-language-team") - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $locale: HLocale( - eval(isUserCoordinatorOfLanguage($locale)) - ) - check: PermissionCheck(action == "manage-language-team", granted == false) -then - check.grant(); -end - - - -/* 'team coordinator' can insert/update/delete language team members */ - -rule TeamCoordinatorModifyLanguageTeamMembers - no-loop - activation-group "permissions" -when - PermissionCheck(action == "insert" || action == "update" || action == "delete", - granted == false) - HLocaleMember() - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $member: HLocaleMember( $locale : supportedLanguage, isUserCoordinatorOfLanguage($locale) ) - check: PermissionCheck( - target == $member, - action == "insert" || action == "update" || action == "delete", - granted == false) -then - check.grant(); -end - - -/***************************************************************************************** - - View Obsolete Project and Project Iteration rules - -******************************************************************************************/ - -rule ViewObsoleteProject - no-loop - activation-group "permissions" -when - check: PermissionCheck(target == "HProject", action == "view-obsolete", granted == false) - Role(name == "admin") -then - check.grant(); -end - -rule ViewObsoleteProjectIteration - no-loop - activation-group "permissions" -when - check: PermissionCheck(target == "HProjectIteration", action == "view-obsolete", granted == false) - Role(name == "admin") -then - check.grant(); -end - -/***************************************************************************************** - - Mark Project and Project Iteration obsolete rules - -******************************************************************************************/ - -rule MarkProjectObsolete - no-loop - activation-group "permissions" -when - $project: HProject() - check: PermissionCheck(target == $project, action == "mark-obsolete", granted == false) - Role(name == "admin") -then - check.grant(); -end - -rule MarkProjectIterationObsolete - no-loop - activation-group "permissions" -when - $iter: HProjectIteration() - check: PermissionCheck(target == $iter, action == "mark-obsolete", granted == false) - Role(name == "admin") -then - check.grant(); -end - - -/***************************************************************************************** - - File Download rules - -******************************************************************************************/ - -/* Permissions to download files. - NOTE: Currently any authenticated user can download files - */ - -rule TranslatorsDownloadFiles - no-loop - activation-group "permissions" -when - authenticatedPerson: HPerson() - $iteration: HProjectIteration() - check: PermissionCheck( - target == $iteration, - action == "download-single" || action == "download-all", - granted == false) -then - check.grant(); -end - -/***************************************************************************************** - - Version Group rules - -******************************************************************************************/ -rule UpdateAndInsertVersionGroup - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "update" || action == "insert" , granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $group: HIterationGroup( - eval(authenticatedPerson.isMaintainer($group)) - ) -then - check.grant(); -end - - -rule ViewObsoleteVersionGroup - no-loop - activation-group "permissions" -when - check: PermissionCheck(target == "HIterationGroup", action == "view-obsolete", granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - eval(authenticatedPerson.isMaintainerOfVersionGroups()) -then - check.grant(); -end - -/***************************************************************************************** - - Copy Trans rules - -******************************************************************************************/ - -/** Admins and Project maintainers can perform copy-trans */ - -rule IterationCopyTrans - no-loop - activation-group "permissions" -when - check: PermissionCheck( action == "copy-trans", granted == false ) - authenticatedPerson: HPerson() - $iteration: HProjectIteration( - eval( authenticatedPerson.isMaintainer( $iteration.getProject() ) ) - ) -then - check.grant(); -end - - -/***************************************************************************************** - - Review translation rules - -******************************************************************************************/ -rule ReviewerReviewTranslation - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "translation-review", granted == false) - $project: HProject( - eval( isUserAllowedAccess($project) ) - ) - $locale: HLocale( - eval( isUserReviewerOfLanguage($locale) ) - ) -then - check.grant(); -end - -rule ProjectMaintainerReviewTranslation - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "translation-review", granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $project: HProject( - eval( authenticatedPerson.isMaintainer($project) ) - ) -then - check.grant(); -end - -/***************************************************************************************** - - Review comment rules - -******************************************************************************************/ -rule LanguageTeamMemberReviewerComment - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "review-comment", granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $project: HProject( - eval( isUserAllowedAccess($project) ) - ) - $locale: HLocale( - eval( isLanguageTeamMember($locale)) - ) -then - check.grant(); -end - -rule ProjectMaintainerReviewerComment - no-loop - activation-group "permissions" -when - check: PermissionCheck(action == "review-comment", granted == false) - authenticatedPerson: HPerson() - eval(authenticatedPerson != null) - $project: HProject( - eval(authenticatedPerson.isMaintainer($project)) - ) -then - check.grant(); -end diff --git a/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/components.xml b/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/components.xml index fa0d655214..381c396c19 100644 --- a/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/components.xml +++ b/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/components.xml @@ -53,16 +53,6 @@ - - - - /security.drl - - - diff --git a/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/persistence.xml b/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/persistence.xml index 3b7d5e8532..4882d1ff39 100644 --- a/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/persistence.xml +++ b/zanata-war/src/main/webapp-jboss/WEB-INF/classes/META-INF/persistence.xml @@ -57,10 +57,6 @@ - - @@ -114,7 +110,6 @@ - diff --git a/zanata-war/src/main/webapp-jboss/WEB-INF/jboss-deployment-structure.xml b/zanata-war/src/main/webapp-jboss/WEB-INF/jboss-deployment-structure.xml index 16f51099db..29cb59a00d 100644 --- a/zanata-war/src/main/webapp-jboss/WEB-INF/jboss-deployment-structure.xml +++ b/zanata-war/src/main/webapp-jboss/WEB-INF/jboss-deployment-structure.xml @@ -9,20 +9,26 @@ + + + + + + + - diff --git a/zanata-war/src/main/webapp-jboss/WEB-INF/web.xml b/zanata-war/src/main/webapp-jboss/WEB-INF/web.xml index 8a3edaf30f..e685d9581c 100644 --- a/zanata-war/src/main/webapp-jboss/WEB-INF/web.xml +++ b/zanata-war/src/main/webapp-jboss/WEB-INF/web.xml @@ -66,12 +66,6 @@ DEFAULT --> - - org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL - ${war_bundles_jsf_impl} - - - + + multiUploadServlet + org.zanata.servlet.MultiFileUploadServlet + + + + multiUploadServlet + /files/upload/* + + gwtServlet org.zanata.webtrans.server.GwtDispatchService diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/activation.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/activation.xhtml deleted file mode 100644 index 72cc62c2f6..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/activation.xhtml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - -

#{messages['jsf.email.activation.register.DearName']}

- -

#{messages['jsf.email.activation.ClickLinkToActivateAccount']}

- -

- - #{messages['jsf.email.activation.Link']} - -

- -

- #{messages['jsf.email.alternate.copyPasteMessage']} -

- -

- - #{applicationConfiguration.serverPath}/account/activate/#{emailServiceImpl.activationKey} - -

- -

- #{messages['jsf.UrlExpireMessage']} -

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_activation.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_activation.xhtml deleted file mode 100644 index d856db2294..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_activation.xhtml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - -

#{messages['jsf.email.activation.profile.DearName']}

- -

#{messages['jsf.email.activation.ClickLinkToActivateAccount']}

- -

- - #{messages['jsf.email.activation.Link']} - -

- -

- #{messages['jsf.email.alternate.copyPasteMessage']} -

- -

- - #{applicationConfiguration.serverPath}/account/activate/#{newProfileAction.activationKey} - -

- -

- #{messages['jsf.UrlExpireMessage']} -

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_admin.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_admin.xhtml deleted file mode 100644 index f5f06c8281..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_admin.xhtml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - -

#{messages['jsf.email.admin.DearAdmin']}

- -

#{messages['jsf.email.admin.UserMessageIntro']}

-
- -
-

#{messages['jsf.email.ReplyInstructions']}

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_coordinator.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_coordinator.xhtml deleted file mode 100644 index 7ba37bb809..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_coordinator.xhtml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - -

#{messages['jsf.email.coordinator.DearCoordinator']}

- -

#{messages['jsf.email.coordinator.UserMessageIntro']}

-
- -
-

#{messages['jsf.email.coordinator.ResponseInstructions']}

- -

- - #{applicationConfiguration.serverPath}/language/view/#{sendEmail.locale.localeId.id} - -

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_role_language.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_role_language.xhtml deleted file mode 100644 index bbbae91b9b..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_role_language.xhtml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - -

#{messages['jsf.email.coordinator.DearCoordinator']}

- -

- #{messages['jsf.email.rolerequest.UserRequestingRole']} -

    - -
  • - #{messages['jsf.Translator']} -
  • -
    - - -
  • - #{messages['jsf.Reviewer']} -
  • -
    - - -
  • - #{messages['jsf.Coordinator']} -
  • -
    -
-

- - -

#{messages['jsf.email.UserMessageIntro']}

-
- -
-
- -

#{messages['jsf.email.rolerequest.AddUserInstructions']}

- -

#{messages['jsf.email.coordinator.ResponseInstructions']}

- -

- - #{applicationConfiguration.serverPath}/language/view/#{sendEmail.locale.localeId.id} - -

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_to_join_group.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_to_join_group.xhtml deleted file mode 100644 index 4c89610537..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_to_join_group.xhtml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - -

#{messages['jsf.email.maintainer.DearMaintainer']}

- -

#{messages['jsf.email.joingrouprequest.RequestingToJoinGroup']}

-
    - - -
  • - #{messages['jsf.Project']}:#{version.projectIteration.project.slug} - #{messages['jsf.Version']}:#{version.projectIteration.slug} -
  • -
    -
    -
- -

#{messages['jsf.email.UserMessageIntro']}

-
- -
-
- -

#{messages['jsf.email.JoinGroupRequest.ResponseInstructions']}

- -

- - #{applicationConfiguration.serverPath}/version-group/view/#{versionGroupJoinAction.slug}#settings-projects - -

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_to_join_language.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_to_join_language.xhtml deleted file mode 100644 index fe75a35f95..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_request_to_join_language.xhtml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - -

#{messages['jsf.email.coordinator.DearCoordinator']}

- -

- #{messages['jsf.email.joinrequest.UserRequestingToJoin']} - -
-

    - -
  • - #{messages['jsf.Translator']} -
  • -
    - - -
  • - #{messages['jsf.Reviewer']} -
  • -
    - - -
  • - #{messages['jsf.Coordinator']} -
  • -
    -
- -

- - -

#{messages['jsf.email.UserMessageIntro']}

-
- -
-
- -

#{messages['jsf.email.joinrequest.AddUserInstructions']}

- -

#{messages['jsf.email.coordinator.ResponseInstructions']}

- -

- - #{applicationConfiguration.serverPath}/language/view/#{sendEmail.locale.localeId.id} - -

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_validation.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_validation.xhtml deleted file mode 100644 index e7a249d2e8..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/email_validation.xhtml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - -

#{messages['jsf.email.accountchange.DearName']}

- -

#{messages['jsf.email.accountchange.Message']} -
#{messages['jsf.email.accountchange.Message2']}

- -

- - #{messages['jsf.email.accountchange.ConfirmationLink']} - -

- -

- #{messages['jsf.email.alternate.copyPasteMessage']} -

- -

- #{messages['jsf.UrlExpireMessage']} -

- -

- - #{applicationConfiguration.serverPath}/account/validate_email/#{profileAction.activationKey} - -

- -
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/password_reset.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/password_reset.xhtml deleted file mode 100644 index 566e242d3e..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/password_reset.xhtml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - -

#{messages['jsf.email.passwordreset.DearName']}

- -

#{messages['jsf.email.passwordreset.FollowLinkToResetPassword']}

- -

#{messages['jsf.email.passwordreset.IgnoreIfNotRequested']}

- -

- - #{applicationConfiguration.serverPath}/account/password_reset/#{passwordResetRequest.activationKey} - -

-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/template_email.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/template_email.xhtml deleted file mode 100644 index ad074e7a69..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/template_email.xhtml +++ /dev/null @@ -1,40 +0,0 @@ - - #{applicationConfiguration.fromEmailAddr} - #{toEmailAddr} - - #{replyToEmail} - #{subject} - - - - No email body template specified. -
-

- - #{messages['jsf.email.YouAreReceivingThisMailBecause']}
- #{emailServiceImpl.receivedReason}
-
-

- -

- #{messages['jsf.email.GeneratedFromZanataServerAt']} - - #{applicationConfiguration.serverPath} - -

- - -
-
diff --git a/zanata-war/src/main/webapp/WEB-INF/facelets/email/username_changed.xhtml b/zanata-war/src/main/webapp/WEB-INF/facelets/email/username_changed.xhtml deleted file mode 100644 index afbba7b135..0000000000 --- a/zanata-war/src/main/webapp/WEB-INF/facelets/email/username_changed.xhtml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - -

#{messages['jsf.email.usernamechange.DearName']}

- -

#{messages['jsf.email.usernamechange.Content']}

- -

#{messages['jsf.email.usernamechange.YourNewUsername']}

- -

#{messages['jsf.email.usernamechange.ResetPassword']}

- -

- - #{messages['jsf.email.usernamechange.ClickLinkForPasswordReset']} - -

-
-
- -
diff --git a/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline.xhtml b/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline.xhtml index b222e0cdac..c0b14324d2 100644 --- a/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline.xhtml +++ b/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline.xhtml @@ -16,15 +16,15 @@

- #{messages['jsf.iteration.CopyTrans.Condition.onContentMismatch']}

+ #{msgs['jsf.iteration.CopyTrans.Condition.onContentMismatch']}

- #{messages['jsf.iteration.CopyTrans.Condition.onContentMismatch.details']}

+ #{msgs['jsf.iteration.CopyTrans.Condition.onContentMismatch.details']}

@@ -34,11 +34,11 @@

- #{messages['jsf.iteration.CopyTrans.Condition.onContextMismatch']} + #{msgs['jsf.iteration.CopyTrans.Condition.onContextMismatch']}

- #{messages['jsf.iteration.CopyTrans.Condition.onContextMismatch.details']} + #{msgs['jsf.iteration.CopyTrans.Condition.onContextMismatch.details']}

@@ -72,11 +72,11 @@

- #{messages['jsf.iteration.CopyTrans.Condition.onProjectMismatch']} + #{msgs['jsf.iteration.CopyTrans.Condition.onProjectMismatch']}

- #{messages['jsf.iteration.CopyTrans.Condition.onProjectMismatch.details']} + #{msgs['jsf.iteration.CopyTrans.Condition.onProjectMismatch.details']}

@@ -112,11 +112,11 @@

- #{messages['jsf.iteration.CopyTrans.Condition.onDocIdMismatch']} + #{msgs['jsf.iteration.CopyTrans.Condition.onDocIdMismatch']}

- #{messages['jsf.iteration.CopyTrans.Condition.onDocIdMismatch.details']} + #{msgs['jsf.iteration.CopyTrans.Condition.onDocIdMismatch.details']}

@@ -149,10 +149,10 @@
  • + value="#{msgs['jsf.CopyTrans.Action.message']}"/>

    + value="#{msgs['jsf.CopyTrans.Action.message2']}"/>

  • diff --git a/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline_modal.xhtml b/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline_modal.xhtml index ac36c9737f..0cbc39489b 100644 --- a/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline_modal.xhtml +++ b/zanata-war/src/main/webapp/WEB-INF/layout/copy_trans_inline_modal.xhtml @@ -9,14 +9,14 @@ role="dialog" aria-hidden="true"> + + + + + + + + - + -
    +
    diff --git a/zanata-war/src/main/webapp/WEB-INF/layout/role_rule_edit_form.xhtml b/zanata-war/src/main/webapp/WEB-INF/layout/role_rule_edit_form.xhtml index 700968d6f5..aef8c8ed65 100644 --- a/zanata-war/src/main/webapp/WEB-INF/layout/role_rule_edit_form.xhtml +++ b/zanata-war/src/main/webapp/WEB-INF/layout/role_rule_edit_form.xhtml @@ -12,7 +12,7 @@ #{messages['jsf.rolerules.PolicyName']} + name="label">#{msgs['jsf.rolerules.PolicyName']} - #{messages['jsf.rolerules.PolicyName.tooltip']} + #{msgs['jsf.rolerules.PolicyName.tooltip']} #{messages['jsf.rolerules.IdentityPattern']} + name="label">#{msgs['jsf.rolerules.IdentityPattern']} - #{messages['jsf.rolerules.IdentityPattern.tooltip']} + #{msgs['jsf.rolerules.IdentityPattern.tooltip']} #{messages['jsf.rolerules.RoleToAssign']} + name="label">#{msgs['jsf.rolerules.RoleToAssign']} - #{messages['jsf.rolerules.RoleToAssign.tooltip']} + #{msgs['jsf.rolerules.RoleToAssign.tooltip']} @@ -57,15 +57,15 @@
    diff --git a/zanata-war/src/main/webapp/WEB-INF/layout/transmemory_edit_form.xhtml b/zanata-war/src/main/webapp/WEB-INF/layout/transmemory_edit_form.xhtml index ec411fc93d..5db9209673 100644 --- a/zanata-war/src/main/webapp/WEB-INF/layout/transmemory_edit_form.xhtml +++ b/zanata-war/src/main/webapp/WEB-INF/layout/transmemory_edit_form.xhtml @@ -12,7 +12,7 @@ #{messages['jsf.transmemory.TransMemoryId']} + name="label">#{msgs['jsf.transmemory.TransMemoryId']} @@ -21,13 +21,13 @@ - #{messages['jsf.transmemory.TransMemoryIdExample']} + #{msgs['jsf.transmemory.TransMemoryIdExample']} - #{messages['jsf.Description']} + #{msgs['jsf.Description']} @@ -39,15 +39,15 @@
    diff --git a/zanata-war/src/main/webapp/WEB-INF/layout/version-group/edit_form.xhtml b/zanata-war/src/main/webapp/WEB-INF/layout/version-group/edit_form.xhtml index 429f02db7c..6163616801 100644 --- a/zanata-war/src/main/webapp/WEB-INF/layout/version-group/edit_form.xhtml +++ b/zanata-war/src/main/webapp/WEB-INF/layout/version-group/edit_form.xhtml @@ -6,7 +6,7 @@ xmlns:a4j="http://richfaces.org/a4j">
    - #{messages['jsf.GroupName']} + #{msgs['jsf.GroupName']} * @@ -17,7 +17,7 @@
    - #{messages['jsf.GroupId']} + #{msgs['jsf.GroupId']} * @@ -36,7 +36,7 @@
    - #{messages['jsf.GroupDescription']} + #{msgs['jsf.GroupDescription']}
    -

    #{messages['jsf.Languages']}

    +

    #{msgs['jsf.Languages']}

    -

    #{messages['jsf.NoActiveLanguages']}

    +

    #{msgs['jsf.NoActiveLanguages']}

    - #{messages['jsf.AddLanguages']} + #{msgs['jsf.AddLanguages']}

    @@ -75,7 +75,7 @@ -

    #{messages['jsf.search.NoResult']}

    +

    #{msgs['jsf.search.NoResult']}

    + title="#{msgs['Languages']}"> @@ -161,14 +161,14 @@ #{versionGroupHomeAction.selectedLocale.retrieveDisplayName()} - #{messages['jsf.Projects']} + #{msgs['jsf.Projects']}
    -

    #{messages['jsf.SelectALanguageFromList']}

    +

    #{msgs['jsf.SelectALanguageFromList']}

    -

    #{messages['jsf.NoProjectsInGroup']}

    +

    #{msgs['jsf.NoProjectsInGroup']}

    - #{messages['jsf.AddProjectVersions']} + #{msgs['jsf.AddProjectVersions']}

    @@ -204,7 +204,7 @@ -

    #{messages['jsf.search.NoResult']}

    +

    #{msgs['jsf.search.NoResult']}

    #{messages['jsf.Missing']} + class="label--danger l--push-left-quarter">#{msgs['jsf.Missing']}
    @@ -257,7 +257,7 @@
    -

    #{messages['jsf.Projects']}

    +

    #{msgs['jsf.Projects']}

    -

    #{messages['jsf.NoProjectsInGroup']}

    +

    #{msgs['jsf.NoProjectsInGroup']}

    - #{messages['jsf.AddProjectVersions']} + #{msgs['jsf.AddProjectVersions']}

    @@ -74,7 +74,7 @@ -

    #{messages['jsf.search.NoResult']}

    +

    #{msgs['jsf.search.NoResult']}

    + title="#{msgs['Projects']}"> @@ -166,14 +166,14 @@ #{versionGroupHomeAction.selectedVersion.project.slug} - #{messages['Languages']} + #{msgs['Languages']}
    -

    #{messages['jsf.SelectAProjectFromList']}

    +

    #{msgs['jsf.SelectAProjectFromList']}

    -

    #{messages['jsf.NoActiveLanguages']}

    +

    #{msgs['jsf.NoActiveLanguages']}

    - #{messages['jsf.AddLanguages']} + #{msgs['jsf.AddLanguages']}

    @@ -209,7 +209,7 @@ -

    #{messages['jsf.search.NoResult']}

    +

    #{msgs['jsf.search.NoResult']}

    #{messages['jsf.Missing']} + class="label--danger">#{msgs['jsf.Missing']} @@ -288,7 +288,7 @@ - - - - - -

    - - - -

    - - - - #{messages['jsf.ProjectName']} - #{selectableVersion.projectIteration.project.name} - - - #{messages['jsf.Version']} - #{selectableVersion.projectIteration.slug} - - - - #{messages['jsf.Actions']} - - - - - - -

    #{messages['jsf.ClickSendMessageToProceedRequest']}

    - - - #{messages['jsf.email.From']} - - - - - #{messages['jsf.email.ReplyAddress']} -
    #{messages['jsf.email.ReplyAddress.description']}
    - -
    - - - #{messages['jsf.email.Subject']} - - - - - #{messages['jsf.AdditionalInfo']} - - - - #{messages['jsf.email.joingrouprequest.AdditionalInfoMessage']} - - -

    - - -
    - -
    -
    - - - -
    - -
    -
    - - - diff --git a/zanata-war/src/main/webapp/WEB-INF/layout/version-group/settings-tab.xhtml b/zanata-war/src/main/webapp/WEB-INF/layout/version-group/settings-tab.xhtml index c188c4aa94..0f5813318a 100644 --- a/zanata-war/src/main/webapp/WEB-INF/layout/version-group/settings-tab.xhtml +++ b/zanata-war/src/main/webapp/WEB-INF/layout/version-group/settings-tab.xhtml @@ -7,7 +7,7 @@ xmlns:f="http://java.sun.com/jsf/core" xmlns:zanata="http://java.sun.com/jsf/composite/zanata"> -

    #{messages['jsf.Settings']}

    +

    #{msgs['jsf.Settings']}

      @@ -17,7 +17,7 @@ id="settings-general_tab" class="js-url-mod is-active" data-content="#settings-general"> - #{messages['jsf.General']} + #{msgs['jsf.General']}
    • @@ -26,7 +26,7 @@ id="settings-languages_tab" class="js-url-mod" data-content="#settings-languages"> - #{messages['jsf.Languages']} + #{msgs['jsf.Languages']}
    • @@ -35,7 +35,7 @@ id="settings-projects_tab" class="js-url-mod" data-content="#settings-projects"> - #{messages['jsf.Projects']} + #{msgs['jsf.Projects']}
    • @@ -44,19 +44,19 @@ id="settings-maintainers_tab" class="js-url-mod" data-content="#settings-maintainers"> - #{messages['jsf.Maintainers']} + #{msgs['jsf.Maintainers']}
    • -

      #{messages['jsf.General']}

      +

      #{msgs['jsf.General']}

      - - #{messages['jsf.ArchiveThisGroup']} + #{msgs['jsf.ArchiveThisGroup']}

      -

      #{messages['jsf.ArchiveGroupMessage']}

      +

      #{msgs['jsf.ArchiveGroupMessage']}

      #{messages['jsf.UnArchiveThisGroup']} + class="i--left i--archive">
      #{msgs['jsf.UnArchiveThisGroup']}

      #{messages['jsf.ActivateGroupMessage']} + class="i--left i--archive"> #{msgs['jsf.ActivateGroupMessage']}

      @@ -97,26 +97,35 @@
    • - #{messages['jsf.Languages']} + #{msgs['jsf.Languages']}

        -
      • #{locale.retrieveDisplayName()} +
      • #{locale.retrieveDisplayName()}[#{locale.localeId}] - - + onbegin="jQuery('#remove-language-#{status.index}').addClass('is-hidden')" + oncomplete="refreshStatistics()" execute="@this" + render="settings-languages-form" + title="#{messages['jsf.group.RemoveLanguage.title']}"> + #{messages['jsf.group.RemoveLanguage.sr.label']} + + + + + +
      • + placeholder="#{msgs['jsf.language.search.placeholder']}"> #{result.retrieveDisplayName()}[#{result.localeId}] @@ -137,14 +146,14 @@
      • - #{messages['jsf.Projects']} + #{msgs['jsf.Projects']}

          -
        • + var="version" varStatus="status"> +
        • @@ -152,18 +161,26 @@ class="i i--version"> #{version.slug} - + onbegin="jQuery('#remove-version-#{status.index}').addClass('is-hidden')" + oncomplete="refreshStatistics()" execute="@this" + render="settings-projects-form" + title="#{messages['jsf.group.RemoveVersion.title']}"> + #{messages['jsf.group.RemoveVersion.sr.label']} + + + + + +
        • + placeholder="#{msgs['jsf.SearchProjects']}"> #{result.project.slug} #{result.slug} @@ -182,24 +199,39 @@
        • - #{messages['jsf.Maintainers']} + #{msgs['jsf.Maintainers']} + + + + +

            -
          • - - #{maintainer.account.username} - #{maintainer.name} +
          • + + #{maintainer.account.username} + + #{maintainer.name} @#{maintainer.account.username} - + onbegin="jQuery('#remove-maintainer-#{status.index}').addClass('is-hidden')" + execute="@this" + render="settings-maintainers-form,maintainers-size,maintainers-list,maintainers-form" + title="#{messages['jsf.group.RemoveMaintainer.title']}"> + #{messages['jsf.group.RemoveMaintainer.sr.label']} + + + + + +
          • @@ -207,7 +239,7 @@
          • + placeholder="#{msgs['jsf.SearchUsers']}"> + onSelectStatus="maintainers-form-loader">
    -

    #{messages['jsf.Documents']}

    +

    #{msgs['jsf.Documents']}

    @@ -62,7 +62,7 @@ listId="documents-document_form" render="documents-document_form, documentsTabDocumentSearchBottom-pager, documentsTabDocumentSearchBottom-page-info" id="documentsTabDocumentSearch" iconClass="i--document" - placeholder="#{messages['jsf.document.search.placeholder']}" + placeholder="#{msgs['jsf.document.search.placeholder']}" actionBean="#{versionHomeAction.documentsTabDocumentFilter}"/>
    @@ -74,14 +74,14 @@

    #{messages['jsf.iteration.NoDocumentInVersion']}

    + class="txt--meta">#{msgs['jsf.iteration.NoDocumentInVersion']}

    - #{messages['jsf.iteration.files.UploadNewSourceDocument']} + #{msgs['jsf.iteration.files.UploadNewSourceDocument']}

    @@ -89,7 +89,7 @@ -

    #{messages['jsf.search.NoResult']}

    +

    #{msgs['jsf.search.NoResult']}

    + title="#{msgs['jsf.tooltip.DocumentOptions']}" href="#">