diff --git a/README.md b/README.md index 72e47920..5e2471fe 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,11 @@ Each extension mentioned above is a separate open-source project and has its own This extension collects telemetry data to help us improve the Java development experience in VS Code. It does not collect any personal information such as names, addresses, or file paths. For more details, see our [privacy statement](http://go.microsoft.com/fwlink/?LinkId=521839). You can disable telemetry collection at any time by changing the `telemetry.enableTelemetry` setting as described in our [FAQ](https://code.visualstudio.com/docs/supporting/faq#_how-to-disable-telemetry-reporting). +## Contributing translations + +See the [localization contributor guide](docs/localization.md) for supported +resources, catalog checks and translation review requirements. + ## License [MIT](https://github.com/Microsoft/vscode-java-pack/blob/master/LICENSE.txt) diff --git a/docs/localization.md b/docs/localization.md new file mode 100644 index 00000000..9c5f51c1 --- /dev/null +++ b/docs/localization.md @@ -0,0 +1,140 @@ +# Localization + +English is the source language. Simplified Chinese (`zh-cn`) is the first +translation. The pack follows VS Code's display language and normal reload +behavior, with English fallback. There is no separate language setting. + +## Manifest resources + +Pack-owned manifest UI text uses semantic `%key%` references in `package.json`. +Keep English defaults in `package.nls.json` and translate every key in +`package.nls..json`. This includes the walkthrough, media alternative +text, command and shortcut captions, settings descriptions and formatter editor +name. Keep the existing English wording when externalizing text. + +Use VS Code locale names (for example `zh-cn`, not `zh_CN`). Preserve product +names, codicons, Markdown structure, link targets and encoded command arguments. +Never translate command IDs, settings keys, enum values, paths or telemetry +identifiers. The pack does not translate its bundled extensions. + +## Native messages and webviews + +The manifest's `l10n: "./l10n"` lets VS Code select the runtime bundle. +Extension-host code uses `vscode.l10n.t("Complete message {0}", value)`. +Do not dynamically translate exception messages or assemble sentences from +translated fragments. Retain original errors in logs and localize the +pack-authored explanation. Dialog actions use message-item object identity, +not comparisons against English or translated captions; cancellation remains +`undefined`. + +All eight webviews are localized: Overview, Help Center, Tips for Beginners, +Extensions Guide, Install JDK, Java Runtime, Project Settings and Formatter +Settings. The legacy Java Runtime page remains supported by its serializer; +the current `java.runtime` command opens Project Settings' JDK page. + +Use `src/l10n/host.ts` for native HTML titles, language attributes, escaping and +the nonce-protected inert JSON bootstrap. Pass only the active +`vscode.l10n.bundle` and `vscode.env.language`; do not discover catalogs, +inspect `navigator.language`, fetch translations, change CSP or expand +`localResourceRoots`. Browser entries import `src/l10n/browser.ts` before +rendering and use `@vscode/l10n`, never `vscode`. Missing bundles or keys use +English; malformed bootstraps are explicit errors. Restored panels rebuild +their titles and bootstrap using the current language. + +Call translation functions lazily at presentation boundaries, not in +module-level metadata before initialization. Keep raw `ProjectType`, +`ExampleKind`, formatter candidates, setting IDs, XML values and telemetry +identities unchanged. Explicit display mappings live in `src/l10n/display.ts` +and `src/formatter-settings/assets/labels.ts`. Never persist translated labels. +For sentences containing links or React nodes, use reorderable placeholders +with `richText` (browser) or `formatHtml` (native HTML) and trusted nodes. +Translations must not supply arbitrary HTML or command URLs. + +## Updating or adding a language + +1. Use a VS Code locale name, such as `zh-cn`, in both + `package.nls..json` and `l10n/bundle.l10n..json`. +2. Keep English defaults in `package.nls.json`. After editing native or browser + messages, run `npm run l10n:export` to deterministically regenerate + `l10n/bundle.l10n.json`. This command intentionally updates the source catalog. +3. Translate every source key in both locale catalogs. Preserve placeholder + names and occurrence counts, but reorder them as needed. Preserve link + targets, encoded arguments, Markdown, codicons and functional symbols. +4. Run `npm run l10n:check`, `npm test` and `npm run build`. The check discovers + every shipped locale, requires matching manifest/runtime locales, verifies + coverage and invariants, and extracts to a temporary directory to detect + drift without rewriting committed catalogs. Add regression cases for new + UI/action behavior. +5. Package with `npx @vscode/vsce@latest package -o vscode-java-pack-localized.vsix`. + Inspect the actual VSIX, not just the checkout: `extension/` must contain + both root manifest catalogs, runtime bundles and all eight browser assets. + `node_modules` is intentionally excluded; browser localization is bundled. + Install the package and verify English, the new language and unsupported + language fallback, including link actions and restored panels. + +### UI validation + +Use AutoTest YAML, stable command IDs/selectors and deterministic text verifiers. +`test-plans/java-webview-migration.yaml` covers the current English command routes; +`test-plans/localization/en-native.yaml` checks native settings actions and restoration; +`test-plans/localization/zh-cn.yaml` contains the Chinese acceptance scenario. +The latter is kept outside the top-level CI discovery glob because ordinary +AutoTest launches do not currently select a display language. + +Before running a translated scenario, verify the runner actually launches VS +Code in that locale and installs the matching language pack. AutoTest 0.7.35 +can install `MS-CEINTL.vscode-language-pack-zh-hans` using `setup.extensions`, +but its YAML parser has no locale/launch-argument field, and its launch path +does not consume the advertised driver `launchArgs` or CLI `--attach` option. +Do not invent YAML fields or treat installing a language pack as selecting it. +Chinese installed-package acceptance therefore requires a runner with working +locale launch support or a manual localized VS Code session. Assert Chinese +text before calling the scenario a pass. English UI checks do not prove this. + +VS Code also suppresses notification toasts when launched with +`--enable-smoke-test-driver`, which AutoTest uses. The English native scenario +therefore checks the AWT commands' persisted settings instead of claiming toast +coverage. The Chinese scenario retains its message assertions for a compatible +launch; selecting Chinese alone does not remove this separate limitation. +Check the English and Chinese native messages and formatter actions in a normal +installed VS Code session before release. Node tests cover translated action +identity, cancellation and reordered message placeholders, not actual toast UI. + +The legacy Runtime serializer and all eight current-language HTML bootstraps +also have executable Node regression coverage. The English native scenario +exercises a real Help Center window reload and restored content/title. Legacy +Runtime restoration, Chinese restoration and actual unsupported-locale fallback +still need installed-app checks; synthetic missing-key/bundle tests do not +replace them. + +### Development-only pseudolocalization + +Use the standard `@vscode/l10n-dev` tooling with VS Code's Pseudo Language +Language Pack to find clipping and concatenated sentences. In a disposable +development checkout, run: + +```powershell +node node_modules\@vscode\l10n-dev\dist\cli.js generate-pseudo package.nls.json l10n\bundle.l10n.json +``` + +This writes adjacent `qps-ploc` catalogs. Use them only in that disposable +checkout, select the Pseudo display language, and reload normally. Never commit, +publish or include these generated catalogs in the release VSIX; they are not +a supported production language. Inspect long labels, accessibility names and +trusted rich-text links as well as overall layout. + +## Scope + +Release notes, README/tutorial prose, external documentation, screenshots, SVG +content and embedded walkthrough media (including `walkthrough/runtime.md`) are +not translated. Pack-owned in-webview UI text and manifest media alternative +text are translated. Bundled extensions retain their own localization ownership. + +## Translation review + +Human review by an independent Simplified Chinese speaker is a release gate; +catalog checks do not establish translation quality. Do not automatically publish +machine translations or call a cloud translation service. Use consistent terms: +runtime = 运行时, project = 项目, classpath = 类路径, formatter = 格式化程序. +Keep Java, JDK, VS Code and extension/product names unchanged. Future +right-to-left languages also require explicit layout qualification. diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json new file mode 100644 index 00000000..c37fd09f --- /dev/null +++ b/l10n/bundle.l10n.json @@ -0,0 +1,589 @@ +{ + "Java Help Center": "Java Help Center", + "Open Project Folder": "Open Project Folder", + "{0} containing your Java project for full features.": "{0} containing your Java project for full features.", + "Open a folder": "Open a folder", + "Project Explorer": "Project Explorer", + "Expand {0} to view your project structure.": "Expand {0} to view your project structure.", + "Java Project Explorer": "Java Project Explorer", + "Running and Debugging": "Running and Debugging", + "Open {0} to start your project.": "Open {0} to start your project.", + "Run and Debug View": "Run and Debug View", + "Testing": "Testing", + "Use {0} to run unit tests.": "Use {0} to run unit tests.", + "Testing View": "Testing View", + "logo": "logo", + "Welcome to use Java Tools": "Welcome to use Java Tools", + "lightweight, performant, powerful.": "lightweight, performant, powerful.", + "Get Started": "Get Started", + "skip": "skip", + "Next Step": "Next Step", + "You're good to go!": "You're good to go!", + "Next, start using Java!": "Next, start using Java!", + "What's next?": "What's next?", + "Loading...": "Loading...", + "Documentation": "Documentation", + "Questions & Issues": "Questions & Issues", + "Create a {0}": "Create a {0}", + "New Project": "New Project", + "Open an {0}": "Open an {0}", + "Existing Project": "Existing Project", + "Take a {0}": "Take a {0}", + "Tour": "Tour", + "General": "General", + "Configure Java Runtime": "Configure Java Runtime", + "Open Java Settings": "Open Java Settings", + "Install Extensions...": "Install Extensions...", + "Configure Formatter Settings": "Configure Formatter Settings", + "Spring": "Spring", + "Spring Boot with VS Code": "Spring Boot with VS Code", + "Spring PetClinic Sample Application": "Spring PetClinic Sample Application", + "Install Spring Boot Extension Pack ...": "Install Spring Boot Extension Pack ...", + "Student": "Student", + "Coding and Debugging Tips": "Coding and Debugging Tips", + "Tutorial: Running and Debugging": "Tutorial: Running and Debugging", + "Tutorial: Testing": "Tutorial: Testing", + "Configure Sources, Dependencies, Output Folder...": "Configure Sources, Dependencies, Output Folder...", + "Quick Start: Jupyter Notebook for Java": "Quick Start: Jupyter Notebook for Java", + "Enable AWT Development": "Enable AWT Development", + "Disable AWT Development": "Disable AWT Development", + "blogs": "blogs", + "Check our {0} to see what's new": "Check our {0} to see what's new", + "{0} Show Help Center when using Java": "{0} Show Help Center when using Java", + "Install": "Install", + "XML extension is recommended to check the syntax when editing pom.xml.": "XML extension is recommended to check the syntax when editing pom.xml.", + "Configure classpath": "Configure classpath", + "Project Settings": "Project Settings", + "The required extension 'redhat.java' is not installed.": "The required extension 'redhat.java' is not installed.", + "Select Source Folder": "Select Source Folder", + "The source path must be contained in the project root folder.": "The source path must be contained in the project root folder.", + "The path {0} has already been a source path.": "The path {0} has already been a source path.", + "Open Log Files": "Open Log Files", + "Failed to update classpaths: {0}": "Failed to update classpaths: {0}", + "Select Output Folder": "Select Output Folder", + "The customized output path must be contained in the project root folder.": "The customized output path must be contained in the project root folder.", + "Cannot set the project root path as the output path.": "Cannot set the project root path as the output path.", + "Yes": "Yes", + "No": "No", + "The contents in {0} will be removed, are you sure to continue?": "The contents in {0} will be removed, are you sure to continue?", + "Select JDK Home": "Select JDK Home", + "Select the installation path of the JDK": "Select the installation path of the JDK", + "Unable to update the project JDK: {0}": "Unable to update the project JDK: {0}", + "Select Jar File": "Select Jar File", + "Jar": "Jar", + "The configuration file: '{0}' does not exist.": "The configuration file: '{0}' does not exist.", + "Unable to load Java runtimes: {0}": "Unable to load Java runtimes: {0}", + "Not a Maven project": "Not a Maven project", + "Active Maven Profiles": "Active Maven Profiles", + "(comma separated)": "(comma separated)", + "Classpath": "Classpath", + "Compiler": "Compiler", + "Maven": "Maven", + "Formatter {0}": "Formatter {0}", + "Project:": "Project:", + "Applying...": "Applying...", + "Apply Settings": "Apply Settings", + "There are no Java projects opened in the current workspace. Please try to {0} or {1}.": "There are no Java projects opened in the current workspace. Please try to {0} or {1}.", + "reload the page": "reload the page", + "open a Java project": "open a Java project", + "The required extension {0} is not installed or it's disabled. Please {1} it in Visual Studio Code and {2} the page after installation.": "The required extension {0} is not installed or it's disabled. Please {1} it in Visual Studio Code and {2} the page after installation.", + "Language Support for Java™ by Red Hat": "Language Support for Java™ by Red Hat", + "install": "install", + "reload": "reload", + "The version of required extension {0} is too stale. Please {1} it and {2} the page.": "The version of required extension {0} is too stale. Please {1} it and {2} the page.", + "update": "update", + "Use '--release' option for cross-compilation (Java 9 and later)": "Use '--release' option for cross-compilation (Java 9 and later)", + "Bytecode version:": "Bytecode version:", + "Source compatibility:": "Source compatibility:", + "Target compatibility:": "Target compatibility:", + "Target compatibility must be equal or greater than source compatibility.": "Target compatibility must be equal or greater than source compatibility.", + "Please make sure to have a compatible JDK configured (currently {0}). You can change the JDK under the {1} tab.": "Please make sure to have a compatible JDK configured (currently {0}). You can change the JDK under the {1} tab.", + "JDK Runtime": "JDK Runtime", + "Enable preview features": "Enable preview features", + "Class File Generation": "Class File Generation", + "Generate debugging information": "Generate debugging information", + "Store information about method parameters": "Store information about method parameters", + "'{0}' is imported by {1}, some changes made to the compiler settings might be lost after reloading. To make permanent changes, please edit the {2} file.": "'{0}' is imported by {1}, some changes made to the compiler settings might be lost after reloading. To make permanent changes, please edit the {2} file.", + "Sources": "Sources", + "Libraries": "Libraries", + "No source paths are configured.": "No source paths are configured.", + "Remove": "Remove", + "Source Paths": "Source Paths", + "{0}Add Source Root...": "{0}Add Source Root...", + "Source Path:": "Source Path:", + "Source Root Path": "Source Root Path", + "Browse...": "Browse...", + "Output Path:": "Output Path:", + "Output Path": "Output Path", + "OK": "OK", + "Cancel": "Cancel", + "Edit": "Edit", + "Path": "Path", + "Output": "Output", + "No libraries are configured.": "No libraries are configured.", + "{0}Add Library...": "{0}Add Library...", + "JDK:": "JDK:", + "Current project JDK (not listed)": "Current project JDK (not listed)", + "Project JDK not available": "Project JDK not available", + "The current project JDK is not in the available runtime list. Refresh JDKs or locate its installation.": "The current project JDK is not in the available runtime list. Refresh JDKs or locate its installation.", + "{0}Refresh JDKs": "{0}Refresh JDKs", + "{0}Find a local JDK...": "{0}Find a local JDK...", + "{0}Download a new JDK...": "{0}Download a new JDK...", + "'{0}' is imported by {1}, changes made to the classpath might be lost after reloading. To make permanent changes, please edit the {2} file.": "'{0}' is imported by {1}, changes made to the classpath might be lost after reloading. To make permanent changes, please edit the {2} file.", + "Java Overview": "Java Overview", + "Start": "Start", + "Create a Maven project using archetypes": "Create a Maven project using archetypes", + "Create a Maven project...": "Create a Maven project...", + "Create a project with Spring Initializr": "Create a project with Spring Initializr", + "Create a Spring Boot project...": "Create a Spring Boot project...", + "Create a project with Quarkus Tools for Visual Studio Code": "Create a project with Quarkus Tools for Visual Studio Code", + "Create a Quarkus project...": "Create a Quarkus project...", + "Create a project with MicroProfile Starter for Visual Studio Code": "Create a project with MicroProfile Starter for Visual Studio Code", + "Create a MicroProfile project...": "Create a MicroProfile project...", + "Key Bindings": "Key Bindings", + "Use IntelliJ IDEA hot keys in VS Code...": "Use IntelliJ IDEA hot keys in VS Code...", + "Use IntelliJ IDEA Key Bindings": "Use IntelliJ IDEA Key Bindings", + "Use Eclipse hot keys in VS Code...": "Use Eclipse hot keys in VS Code...", + "Use Eclipse Key Bindings": "Use Eclipse Key Bindings", + "Extensions": "Extensions", + "Install the Java language support extension...": "Install the Java language support extension...", + "Install Language Support for Java by Red Hat": "Install Language Support for Java by Red Hat", + "Install the Debugger for Java extension...": "Install the Debugger for Java extension...", + "Install Debugger for Java": "Install Debugger for Java", + "Install the Java Test Runner extension...": "Install the Java Test Runner extension...", + "Install Java Test Runner": "Install Java Test Runner", + "Install the Maven for Java extension...": "Install the Maven for Java extension...", + "Install Maven for Java": "Install Maven for Java", + "Install SonarLint...": "Install SonarLint...", + "Install SonarLint": "Install SonarLint", + "Install the Tomcat for Java extension...": "Install the Tomcat for Java extension...", + "Install Tomcat for Java": "Install Tomcat for Java", + "Install the Checkstyle for Java extension...": "Install the Checkstyle for Java extension...", + "Install Checkstyle for Java": "Install Checkstyle for Java", + "Schema validation when editing pom.xml...": "Schema validation when editing pom.xml...", + "Install XML extension": "Install XML extension", + "Install the Project Manager for Java extension...": "Install the Project Manager for Java extension...", + "Install Project Manager for Java": "Install Project Manager for Java", + "Learn how to work with Spring Boot projects in VS Code": "Learn how to work with Spring Boot projects in VS Code", + "Run PetClinic sample app in VS Code": "Run PetClinic sample app in VS Code", + "Install Spring Boot Extension Pack...": "Install Spring Boot Extension Pack...", + "Install Spring Boot Extension Pack": "Install Spring Boot Extension Pack", + "Microservices": "Microservices", + "Learn how to work with Kubernetes in VS Code": "Learn how to work with Kubernetes in VS Code", + "Kubernetes in VS Code": "Kubernetes in VS Code", + "Learn how to work with Docker in VS Code": "Learn how to work with Docker in VS Code", + "Docker in VS Code": "Docker in VS Code", + "Marketplace link for Extension Pack for MicroProfile": "Marketplace link for Extension Pack for MicroProfile", + "Extension Pack for MicroProfile in VS Code": "Extension Pack for MicroProfile in VS Code", + "Marketplace link for Quarkus Tools for VS Code": "Marketplace link for Quarkus Tools for VS Code", + "Quarkus Tools for VS Code": "Quarkus Tools for VS Code", + "Install Kubernetes extension...": "Install Kubernetes extension...", + "Install Kubernetes Extension": "Install Kubernetes Extension", + "Install Docker extension...": "Install Docker extension...", + "Install Docker Extension": "Install Docker Extension", + "Install Extension Pack for MicroProfile...": "Install Extension Pack for MicroProfile...", + "Install Extension Pack for MicroProfile": "Install Extension Pack for MicroProfile", + "Install Quarkus extension...": "Install Quarkus extension...", + "Install Quarkus Extension": "Install Quarkus Extension", + "Help": "Help", + "Report issues or request features": "Report issues or request features", + "Tweet us your feedback": "Tweet us your feedback", + "Twitter": "Twitter", + "Learn": "Learn", + "Open Java Beginner Tips View": "Open Java Beginner Tips View", + "Java Beginner Tips": "Java Beginner Tips", + "Learn 1 min {0} tutorial, common shortcuts for {1} and {2}, and {3}.": "Learn 1 min {0} tutorial, common shortcuts for {1} and {2}, and {3}.", + "Quick Start": "Quick Start", + "Code Editing": "Code Editing", + "Debugging": "Debugging", + "FAQ": "FAQ", + "Open Java Tutorials": "Open Java Tutorials", + "Java Tutorials": "Java Tutorials", + "Learn how to {0} and {1} in VS Code.": "Learn how to {0} and {1} in VS Code.", + "Open Java Debugging Tutorial": "Open Java Debugging Tutorial", + "debug Java apps": "debug Java apps", + "Open Java Testing Tutorial": "Open Java Testing Tutorial", + "run JUnit tests": "run JUnit tests", + "Configuration": "Configuration", + "Open Java Runtime Guide": "Open Java Runtime Guide", + "Setup JDKs for projects and VS Code Java.": "Setup JDKs for projects and VS Code Java.", + "Open Extensions Guide": "Open Extensions Guide", + "Extensions Guide": "Extensions Guide", + "Recommended extensions for Java development.": "Recommended extensions for Java development.", + "Java Settings": "Java Settings", + "Show the Java settings.": "Show the Java settings.", + "Show overview page when using Java": "Show overview page when using Java", + "Default project": "Default project", + "Unmanaged folder": "Unmanaged folder", + "Gradle": "Gradle", + "Others": "Others", + "Specify Java runtime to launch Language Server": "Specify Java runtime to launch Language Server", + "{0} is not a valid JDK home directory.": "{0} is not a valid JDK home directory.", + "Java {0} or more recent is required to launch the Java Language Server. \"{1}\" doesn't meet the requirement.": "Java {0} or more recent is required to launch the Java Language Server. \"{1}\" doesn't meet the requirement.", + "Unable to refresh Configure Java Runtime: {0}": "Unable to refresh Configure Java Runtime: {0}", + "Unable to list installed project JDKs": "Unable to list installed project JDKs", + "Unable to read runtime information for project \"{0}\" ({1})": "Unable to read runtime information for project \"{0}\" ({1})", + "Unable to list projects from Project Manager for workspace \"{0}\"": "Unable to list projects from Project Manager for workspace \"{0}\"", + "Unable to list projects from the Java language server": "Unable to list projects from the Java language server", + "Project settings are not available from redhat.java.": "Project settings are not available from redhat.java.", + "Project type information is unavailable.": "Project type information is unavailable.", + "Language Support for Java (redhat.java) is unavailable. Check that it is installed and enabled.": "Language Support for Java (redhat.java) is unavailable. Check that it is installed and enabled.", + "redhat.java reports an error. Open the Java logs for details.": "redhat.java reports an error. Open the Java logs for details.", + "The runtime reported by redhat.java uses Java {0}, below the required Java {1}. Open the Java logs for details.": "The runtime reported by redhat.java uses Java {0}, below the required Java {1}. Open the Java logs for details.", + "The configured 'java.jdt.ls.java.home' uses Java {0}, below the required Java {1}. redhat.java reports a different language-server runtime.": "The configured 'java.jdt.ls.java.home' uses Java {0}, below the required Java {1}. redhat.java reports a different language-server runtime.", + "The configured 'java.jdt.ls.java.home' differs from the runtime reported by redhat.java. Open the Java logs for details.": "The configured 'java.jdt.ls.java.home' differs from the runtime reported by redhat.java. Open the Java logs for details.", + "Configure Runtime for Language Server": "Configure Runtime for Language Server", + "{0}Java Language Server requires a JDK {1}+ to launch itself. Your projects can use older JDKs.": "{0}Java Language Server requires a JDK {1}+ to launch itself. Your projects can use older JDKs.", + "Language server runtime reported by redhat.java: {0} (Java {1}).": "Language server runtime reported by redhat.java: {0} (Java {1}).", + "Language server runtime information has not been reported by redhat.java.": "Language server runtime information has not been reported by redhat.java.", + "{0} for details. Runtime selection and startup diagnostics are provided by redhat.java.": "{0} for details. Runtime selection and startup diagnostics are provided by redhat.java.", + "Open Java Logs": "Open Java Logs", + "Refresh{0}": "Refresh{0}", + "For projects managed by build tools, Java version is specified in build scripts(e.g. pom.xml).": "For projects managed by build tools, Java version is specified in build scripts(e.g. pom.xml).", + "For projects managed by build tools, Java version is specified in build scripts(e.g. build.gradle).": "For projects managed by build tools, Java version is specified in build scripts(e.g. build.gradle).", + "For folders containing .java files, but not managed by build tools like Maven/Gradle, a default JDK is used.": "For folders containing .java files, but not managed by build tools like Maven/Gradle, a default JDK is used.", + "Configure Runtime for Projects": "Configure Runtime for Projects", + "Language server runtime information is not available yet. Use Refresh after redhat.java starts, or {0} for details.": "Language server runtime information is not available yet. Use Refresh after redhat.java starts, or {0} for details.", + "open the Java logs": "open the Java logs", + "JDK {0}+ is required for the language server only; your projects can use older JDKs. {1}.": "JDK {0}+ is required for the language server only; your projects can use older JDKs. {1}.", + "Open language-server runtime settings": "Open language-server runtime settings", + "Manage Java runtime for your projects. If you don't have a valid Java runtime, you can {0} one.": "Manage Java runtime for your projects. If you don't have a valid Java runtime, you can {0} one.", + "download": "download", + "Project Name": "Project Name", + "Type": "Type", + "Java Version": "Java Version", + "Project information could not be fully loaded. Please refresh to try again.": "Project information could not be fully loaded. Please refresh to try again.", + "No project detected yet. Please refresh later if Java extension is importing your projects.": "No project detected yet. Please refresh later if Java extension is importing your projects.", + "For projects managed by build tools, Java version is specified in build scripts. E.g. to use Java 8, add below lines in {0}:": "For projects managed by build tools, Java version is specified in build scripts. E.g. to use Java 8, add below lines in {0}:", + "Locate an {0}": "Locate an {0}", + "Existing JDK": "Existing JDK", + "Reload": "Reload", + "Install a {0}": "Install a {0}", + "New JDK": "New JDK", + "Install New JDK": "Install New JDK", + "You need to enable JavaScript to run this app.": "You need to enable JavaScript to run this app.", + "Adoptium's Temurin": "Adoptium's Temurin", + "After you finish JDK installation, please reload Visual Studio Code to make it effective.": "After you finish JDK installation, please reload Visual Studio Code to make it effective.", + "Reload Window": "Reload Window", + "Having trouble?": "Having trouble?", + " (LTS)": " (LTS)", + "Download": "Download", + "Version": "Version", + "JVM": "JVM", + "hotspot": "hotspot", + "The setting has no valid 'id' property.": "The setting has no valid 'id' property.", + "The setting has no valid 'value' property.": "The setting has no valid 'value' property.", + "\"{0}\" is not supported in id: \"{1}\".": "\"{0}\" is not supported in id: \"{1}\".", + "Retry": "Retry", + "Open Settings": "Open Settings", + "Failed to get the profile content from uri: {0}. Do you want to retry?": "Failed to get the profile content from uri: {0}. Do you want to retry?", + "The active formatter profile does not exist or is not remote, please check it in the Settings and try again.": "The active formatter profile does not exist or is not remote, please check it in the Settings and try again.", + "Java Formatter Settings": "Java Formatter Settings", + "The extension 'redhat.java' is not installed. Please install it and run this command again.": "The extension 'redhat.java' is not installed. Please install it and run this command again.", + "The extension version of 'redhat.java' is too stale. Please install at least {0} and run this command again.": "The extension version of 'redhat.java' is too stale. Please install at least {0} and run this command again.", + "The current profile is invalid, please check it in the Settings and try again.": "The current profile is invalid, please check it in the Settings and try again.", + "Formatter Profile settings have been changed, do you want to reload this editor?": "Formatter Profile settings have been changed, do you want to reload this editor?", + "No active Formatter Profile found, do you want to create a default one?": "No active Formatter Profile found, do you want to create a default one?", + "Open in read-only mode": "Open in read-only mode", + "Download and use it locally": "Download and use it locally", + "The active formatter profile is remote, do you want to open it in read-only mode or download and use it locally?": "The active formatter profile is remote, do you want to open it in read-only mode or download and use it locally?", + "Generate a default profile": "Generate a default profile", + "The active formatter profile does not exist, please check it in the Settings and try again.": "The active formatter profile does not exist, please check it in the Settings and try again.", + "Indentation policy": "Indentation policy", + "Tab size": "Tab size", + "Detect indentation from file content": "Detect indentation from file content", + "In control statements": "In control statements", + "Before 'while' in a 'do' statement": "Before 'while' in a 'do' statement", + "Before 'finally' in a 'try' statement": "Before 'finally' in a 'try' statement", + "Before 'else' in an 'if' statement": "Before 'else' in an 'if' statement", + "Before 'catch' in a 'try' statement": "Before 'catch' in a 'try' statement", + "Before closing brace in array initializer": "Before closing brace in array initializer", + "After opening brace in array initializer": "After opening brace in array initializer", + "After annotation": "After annotation", + "After annotation on parameters": "After annotation on parameters", + "After annotation on packages": "After annotation on packages", + "After annotation on enum constants": "After annotation on enum constants", + "Before empty statement": "Before empty statement", + "In empty class declaration": "In empty class declaration", + "Reserve line for class declaration": "Reserve line for class declaration", + "Reserve line for record declaration": "Reserve line for record declaration", + "Reserve line for record constructor": "Reserve line for record constructor", + "In empty method body": "In empty method body", + "Reserve line for method body": "Reserve line for method body", + "In empty enum declaration": "In empty enum declaration", + "Reserve line for enum declaration": "Reserve line for enum declaration", + "In empty enum constant": "In empty enum constant", + "Reserve line for enum constant declaration": "Reserve line for enum constant declaration", + "In empty anonymous type declaration": "In empty anonymous type declaration", + "Reserve line for anonymous type declaration": "Reserve line for anonymous type declaration", + "In empty annotation declaration": "In empty annotation declaration", + "Reserve line for annotation declaration": "Reserve line for annotation declaration", + "Between class declarations": "Between class declarations", + "Between import groups": "Between import groups", + "Before package declarations": "Before package declarations", + "Before import declarations": "Before import declarations", + "Between member type declarations": "Between member type declarations", + "Empty lines to preserve": "Empty lines to preserve", + "Maximum line width": "Maximum line width", + "Maximum comment line length": "Maximum comment line length", + "Indent wrapped parameter description": "Indent wrapped parameter description", + "Enable header comment formatting": "Enable header comment formatting", + "Enable comment formatting": "Enable comment formatting", + "Enable block comment formatting": "Enable block comment formatting", + "Enable line comment formatting": "Enable line comment formatting", + "Count line length from starting position": "Count line length from starting position", + "Remove blank lines in comment": "Remove blank lines in comment", + "Remove blank lines in Javadoc": "Remove blank lines in Javadoc", + "Remove blank lines in block comment": "Remove blank lines in block comment", + "Use On/Off tags": "Use On/Off tags", + "Before first initializer": "Before first initializer", + "After closing parenthesis in cast": "After closing parenthesis in cast", + "After closing angle bracket in type": "After closing angle bracket in type", + "tab": "tab", + "space": "space", + "never": "never", + "if empty": "if empty", + "if at most one item": "if at most one item", + "Indentation": "Indentation", + "Blank line": "Blank line", + "Comment": "Comment", + "Insert Line": "Insert Line", + "Braced type": "Braced type", + "Braced record": "Braced record", + "Braced enum": "Braced enum", + "Annotation and anonymous": "Annotation and anonymous", + "Whitespace": "Whitespace", + "Wrapping": "Wrapping", + "Blank Lines": "Blank Lines", + "Java Formatter Settings (Read Only)": "Java Formatter Settings (Read Only)", + "Download and edit profile": "Download and edit profile", + "Download and Edit": "Download and Edit", + "When enabled, the indentation settings will be overriden based on the file contents.": "When enabled, the indentation settings will be overriden based on the file contents.", + "Java Extensions Guide": "Java Extensions Guide", + "Basics": "Basics", + "Frameworks": "Frameworks", + "Application Servers": "Application Servers", + "Keymaps": "Keymaps", + "Language Support for Java by Red Hat": "Language Support for Java by Red Hat", + "Debugger for Java": "Debugger for Java", + "Project Manager for Java": "Project Manager for Java", + "Test Runner for Java": "Test Runner for Java", + "Maven for Java": "Maven for Java", + "SonarLint": "SonarLint", + "Spring Boot Extension Pack": "Spring Boot Extension Pack", + "Extension Pack for MicroProfile": "Extension Pack for MicroProfile", + "Quarkus": "Quarkus", + "Community Server Connectors": "Community Server Connectors", + "Eclipse Keymap": "Eclipse Keymap", + "IntelliJ IDEA Keybindings": "IntelliJ IDEA Keybindings", + "Java Linting, Intellisense, formatting, refactoring, Maven/Gradle support and more.": "Java Linting, Intellisense, formatting, refactoring, Maven/Gradle support and more.", + "Debug Java applications.": "Debug Java applications.", + "Manage Java projects, dependencies, and generate packages.": "Manage Java projects, dependencies, and generate packages.", + "Run and debug JUnit & TestNG test cases.": "Run and debug JUnit & TestNG test cases.", + "Manage Maven projects, work with goals & dependencies, generate projects from archetypes.": "Manage Maven projects, work with goals & dependencies, generate projects from archetypes.", + "Detect and fix quality issues as you write code.": "Detect and fix quality issues as you write code.", + "Spring Boot-specific support for \".java\" files. As well as validation and content assist for Spring Boot \"application.properties\", \"application.yml\" properties files.": "Spring Boot-specific support for \".java\" files. As well as validation and content assist for Spring Boot \"application.properties\", \"application.yml\" properties files.", + "A collection of extensions to develop Java microservices with Eclipse MicroProfile": "A collection of extensions to develop Java microservices with Eclipse MicroProfile", + "Quarkus Tools for Visual Studio Code.": "Quarkus Tools for Visual Studio Code.", + "Manage and publish to servers and runtimes like Tomcat, Apache Felix, and Karaf.": "Manage and publish to servers and runtimes like Tomcat, Apache Felix, and Karaf.", + "Port of Eclipse keyboard shortcuts.": "Port of Eclipse keyboard shortcuts.", + "Port of IntelliJ IDEA Keybindings, including for WebStorm, PyCharm, PHP Storm, etc.": "Port of IntelliJ IDEA Keybindings, including for WebStorm, PyCharm, PHP Storm, etc.", + "Learn More": "Learn More", + "Install Selected": "Install Selected", + "Install All": "Install All", + "Install Selected ({0})": "Install Selected ({0})", + "Clean and Restart": "Clean and Restart", + "Java extension cannot start due to corrupted workspace cache, please try to clean the workspace.": "Java extension cannot start due to corrupted workspace cache, please try to clean the workspace.", + "Maven extension is recommended to help create Java projects and work with custom goals.": "Maven extension is recommended to help create Java projects and work with custom goals.", + "Spring Initializr extension is recommended to help create Spring Boot projects and manage dependencies.": "Spring Initializr extension is recommended to help create Spring Boot projects and manage dependencies.", + "Quarkus Tools for Visual Studio Code is recommended to help create Quarkus projects and for an all-in-one Quarkus application development experience.": "Quarkus Tools for Visual Studio Code is recommended to help create Quarkus projects and for an all-in-one Quarkus application development experience.", + "MicroProfile Starter for Visual Studio Code is recommended to generate starter projects for Eclipse MicroProfile.": "MicroProfile Starter for Visual Studio Code is recommended to generate starter projects for Eclipse MicroProfile.", + "Installing {0}...": "Installing {0}...", + "Successfully installed {0}.": "Successfully installed {0}.", + "Unable to update Java AWT development settings: {0}": "Unable to update Java AWT development settings: {0}", + "Java AWT development is enabled.": "Java AWT development is enabled.", + "Java AWT development is disabled.": "Java AWT development is disabled.", + "Tips for Beginners": "Tips for Beginners", + "Open...": "Open...", + "Open Folder...": "Open Folder...", + "In this 1-minute tutorial, we'll show you how to create a quick-start Java program in VS Code.": "In this 1-minute tutorial, we'll show you how to create a quick-start Java program in VS Code.", + "Setup the Workspace": "Setup the Workspace", + "VS Code Java works directly with {0} that have source code. To setup the workspace, simply open a folder using File > {1}": "VS Code Java works directly with {0} that have source code. To setup the workspace, simply open a folder using File > {1}", + "folders": "folders", + "Create a Class": "Create a Class", + "A program needs an entry and a Java program needs a class to host its entry. To create a class for our quick-start program, {0} and set its name to {1}.{2}Now you can put the code in the new file:": "A program needs an entry and a Java program needs a class to host its entry. To create a class for our quick-start program, {0} and set its name to {1}.{2}Now you can put the code in the new file:", + "Create a File": "Create a File", + "Run the program": "Run the program", + "To run the program, press {0}. By default, the program is launched in the {1}. You should already see the output there.": "To run the program, press {0}. By default, the program is launched in the {1}. You should already see the output there.", + "F5": "F5", + "Integrated Terminal": "Integrated Terminal", + "How to Debug?": "How to Debug?", + "When you press {0}, you are already debugging. Try setting some breakpoint by clicking on the line numbers before each code line and run the program again. You'll see the execution paused at the breakpoint.{1}While debugging, switch to the {2} to see the variables and call stacks.": "When you press {0}, you are already debugging. Try setting some breakpoint by clicking on the line numbers before each code line and run the program again. You'll see the execution paused at the breakpoint.{1}While debugging, switch to the {2} to see the variables and call stacks.", + "Debug View": "Debug View", + "Congratulations!": "Congratulations!", + "Now the quick-start program is running and you are free to build more.{0}What you saw is just a tiny part of VS Code Java. You can do much more with it.": "Now the quick-start program is running and you are free to build more.{0}What you saw is just a tiny part of VS Code Java. You can do much more with it.", + "Feedback Channels": "Feedback Channels", + "VS Code Java is new, and we are here to help.": "VS Code Java is new, and we are here to help.", + "Ask Questions": "Ask Questions", + "{0} Gitter channel is recommended to ask for help": "{0} Gitter channel is recommended to ask for help", + "vscode-java": "vscode-java", + "Open Issues": "Open Issues", + "{0} GitHub repo is recommended for opening bugs": "{0} GitHub repo is recommended for opening bugs", + "vscode-java-pack": "vscode-java-pack", + "Other Feedback": "Other Feedback", + "{0} is the handle to mention on twitter": "{0} is the handle to mention on twitter", + "@VSCodeJava": "@VSCodeJava", + "Why do I see the JDK errors?": "Why do I see the JDK errors?", + "{0} to run the installed Java language support (redhat.java) extension. A compatible bundled runtime can satisfy this requirement; otherwise, a compatible local JDK is needed. To set the language-server launch JDK explicitly, configure {1}. Runtime selection and startup diagnostics are provided by redhat.java; {2} for details.": "{0} to run the installed Java language support (redhat.java) extension. A compatible bundled runtime can satisfy this requirement; otherwise, a compatible local JDK is needed. To set the language-server launch JDK explicitly, configure {1}. Runtime selection and startup diagnostics are provided by redhat.java; {2} for details.", + "{0} is required": "{0} is required", + "The {0} page configures project JDKs, not the language-server launch JDK. Your projects can use older JDKs independently of the tooling requirement.": "The {0} page configures project JDKs, not the language-server launch JDK. Your projects can use older JDKs independently of the tooling requirement.", + "Can I run my Java 8 project with JDK 1.8?": "Can I run my Java 8 project with JDK 1.8?", + "Yes. The JDK {0} requirement is just for running the Java language support (redhat.java) extension itself. You can still configure a different runtime {1} via the user setting {2}. The extension will pick a matching JDK to compile/run your project according to the compiler version specified by the project build file.": "Yes. The JDK {0} requirement is just for running the Java language support (redhat.java) extension itself. You can still configure a different runtime {1} via the user setting {2}. The extension will pick a matching JDK to compile/run your project according to the compiler version specified by the project build file.", + "JDK for your project": "JDK for your project", + "Why do I see tons of problems and red squiggles?": "Why do I see tons of problems and red squiggles?", + "The problems are from VS Code Java when it tries to compile and build your codebase. If you experience this on your first use, it's possibly because of {0}. To fix it, you probably want to start from fixing the project configuration files, e.g. {1} and {2}. After you make changes to those files, try {3} and {4}.": "The problems are from VS Code Java when it tries to compile and build your codebase. If you experience this on your first use, it's possibly because of {0}. To fix it, you probably want to start from fixing the project configuration files, e.g. {1} and {2}. After you make changes to those files, try {3} and {4}.", + "missing dependencies": "missing dependencies", + "Update Project Configuration": "Update Project Configuration", + "Force Compilation": "Force Compilation", + "It can also happen after you work with one project for a while. Try {0} to get rid of any intermediate output from the language server.": "It can also happen after you work with one project for a while. Try {0} to get rid of any intermediate output from the language server.", + "Clean Workspace": "Clean Workspace", + "If the problem persists, follow the {0}. For advanced users, the {1} and {2} will definitely help you understand what is going on.": "If the problem persists, follow the {0}. For advanced users, the {1} and {2} will definitely help you understand what is going on.", + "Troubleshooting Guide": "Troubleshooting Guide", + "Client Logs": "Client Logs", + "Server Logs": "Server Logs", + "Why can't I see any IntelliSense suggestions?": "Why can't I see any IntelliSense suggestions?", + "VS Code Java needs to compile your code before it can provide suggestions. When it's working, you should see a spinning 🔄 on the right end of the status bar. And it will show 👍 when it's done. And you should be able to use all the features.": "VS Code Java needs to compile your code before it can provide suggestions. When it's working, you should see a spinning 🔄 on the right end of the status bar. And it will show 👍 when it's done. And you should be able to use all the features.", + "It could take longer for the language server to load a project which references lots of dependencies. Those dependencies need to be resolved and downloaded from the internet. So the network connection plays a critical role in the process.": "It could take longer for the language server to load a project which references lots of dependencies. Those dependencies need to be resolved and downloaded from the internet. So the network connection plays a critical role in the process.", + "Can I use Lombok?": "Can I use Lombok?", + "Yes. You'll need to install the {0} extension, which enables VS Code to process Lombok annotations. To learn more about alternatives and details, visit {1}.": "Yes. You'll need to install the {0} extension, which enables VS Code to process Lombok annotations. To learn more about alternatives and details, visit {1}.", + "Lombok": "Lombok", + "this page": "this page", + "Can I develop Android apps using VS Code Java?": "Can I develop Android apps using VS Code Java?", + "Sorry, it's not supported now.": "Sorry, it's not supported now.", + "How to troubleshoot the problems?": "How to troubleshoot the problems?", + "You could click {0} -> {1} to get the logs. Also learn more at {2}.": "You could click {0} -> {1} to get the logs. Also learn more at {2}.", + "F1": "F1", + "Java: Open all log files": "Java: Open all log files", + "Ctrl + F5": "Ctrl + F5", + "⌃ F5": "⌃ F5", + "Shift + F11": "Shift + F11", + "⇧ F11": "⇧ F11", + "Ctrl + Shift + F5": "Ctrl + Shift + F5", + "⇧ ⌘ F5": "⇧ ⌘ F5", + "Shift + F5": "Shift + F5", + "⇧ F5": "⇧ F5", + "One of the key features of Visual Studio Code is its great debugging support. VS Code's built-in debugger helps accelerate your edit, compile and debug loop.": "One of the key features of Visual Studio Code is its great debugging support. VS Code's built-in debugger helps accelerate your edit, compile and debug loop.", + "Start Debugging": "Start Debugging", + "There are multiple ways to start debugging a Java program. By pressing {0}, the current program will be launched. You can also start by clicking the {1} codelens on top of the {2} function. This is super handy when you have multiple main entries. You can also launch a program {3} debugging by pressing {4}.": "There are multiple ways to start debugging a Java program. By pressing {0}, the current program will be launched. You can also start by clicking the {1} codelens on top of the {2} function. This is super handy when you have multiple main entries. You can also launch a program {3} debugging by pressing {4}.", + "\"Debug\"": "\"Debug\"", + "without": "without", + "By default, VS Code Java launches the program using {0}. As you enter the debug mode, you should also see the {1}. This view shows all the runtime info of your program.": "By default, VS Code Java launches the program using {0}. As you enter the debug mode, you should also see the {1}. This view shows all the runtime info of your program.", + "Debug Configurations": "Debug Configurations", + "VS Code Java automatically generates debug configurations. In VS Code, those configurations are called {0} and they are persisted in {1}. To work with more sophisticated debug scenarios, please explore the {2} that are supported by VS Code.": "VS Code Java automatically generates debug configurations. In VS Code, those configurations are called {0} and they are persisted in {1}. To work with more sophisticated debug scenarios, please explore the {2} that are supported by VS Code.", + "Launch Configurations": "Launch Configurations", + "Launch Options": "Launch Options", + "Breakpoints": "Breakpoints", + "Breakpoints can be toggled by clicking on the editor margin or using {0} on the current line. Finer breakpoint control (enable/disable/reapply) can be done in the Debug View's BREAKPOINTS section.": "Breakpoints can be toggled by clicking on the editor margin or using {0} on the current line. Finer breakpoint control (enable/disable/reapply) can be done in the Debug View's BREAKPOINTS section.", + "F9": "F9", + "You can also set {0} based on expressions, hit counts, or a combination of both.": "You can also set {0} based on expressions, hit counts, or a combination of both.", + "Conditional Breakpoints": "Conditional Breakpoints", + "Expression condition": "Expression condition", + "The breakpoint will be hit whenever the expression evaluates to {0}": "The breakpoint will be hit whenever the expression evaluates to {0}", + "Hit count": "Hit count", + "The 'hit count' controls how many times a breakpoint needs to be hit before it will 'break' execution": "The 'hit count' controls how many times a breakpoint needs to be hit before it will 'break' execution", + "You can add a condition and/or hit count when creating the breakpoint (with the {0} action) or when modifying an existing one (with the Edit Breakpoint action). In both cases, an inline text box with a drop-down menu opens where you can enter expressions.": "You can add a condition and/or hit count when creating the breakpoint (with the {0} action) or when modifying an existing one (with the Edit Breakpoint action). In both cases, an inline text box with a drop-down menu opens where you can enter expressions.", + "Add Conditional Breakpoint": "Add Conditional Breakpoint", + "Logpoints": "Logpoints", + "A Logpoint is a variant of a breakpoint that does not \"break\" into the debugger but instead logs a message to the console. Logpoints are especially useful for injecting logging while debugging production servers that cannot be paused or stopped.": "A Logpoint is a variant of a breakpoint that does not \"break\" into the debugger but instead logs a message to the console. Logpoints are especially useful for injecting logging while debugging production servers that cannot be paused or stopped.", + "A Logpoint is represented by a ♦️ shaped icon. Log messages are plain text but can include expressions to be evaluated within curly braces ('{ }').": "A Logpoint is represented by a ♦️ shaped icon. Log messages are plain text but can include expressions to be evaluated within curly braces ('{ }').", + "Debug Actions": "Debug Actions", + "Once a debug session starts, the Debug toolbar will appear on the top of the editor. You can control the execution flow using the actions below.": "Once a debug session starts, the Debug toolbar will appear on the top of the editor. You can control the execution flow using the actions below.", + "Continue/Pause": "Continue/Pause", + "Step Over": "Step Over", + "F10": "F10", + "Step Into": "Step Into", + "F11": "F11", + "Step Out": "Step Out", + "Restart": "Restart", + "Stop": "Stop", + "Inspect Variables": "Inspect Variables", + "Variables can be inspected in the {0} section of the Debug view or by hovering over their source in the editor. Variable values and expression evaluation are relative to the selected stack frame in the {1} section.": "Variables can be inspected in the {0} section of the Debug view or by hovering over their source in the editor. Variable values and expression evaluation are relative to the selected stack frame in the {1} section.", + "VARIABLES": "VARIABLES", + "CALL STACK": "CALL STACK", + "Variable values can be modified with the {0} action from the variable's context menu. Or you can {1} the value and enter a new one. Variables and expressions can also be evaluated and watched in the Debug view's {2} section.": "Variable values can be modified with the {0} action from the variable's context menu. Or you can {1} the value and enter a new one. Variables and expressions can also be evaluated and watched in the Debug view's {2} section.", + "Set Value": "Set Value", + "double-click": "double-click", + "WATCH": "WATCH", + "Hot Code Replace ⚡": "Hot Code Replace ⚡", + "Yes, you can apply code changes without restarting the running program. Click on the {0} icon in the {1} to apply code changes. When you see failures, don't worry. It is safe to continue running the program, but you may notice discrepancies between the source code and the program.": "Yes, you can apply code changes without restarting the running program. Click on the {0} icon in the {1} to apply code changes. When you see failures, don't worry. It is safe to continue running the program, but you may notice discrepancies between the source code and the program.", + "debug toolbar": "debug toolbar", + "Limitations": "Limitations", + "Hot Code Replace (HCR) sounds magical but it does have limitations. In short, you can only change the code inside an existing function. Here are some scenarios that HCR will {0} work:": "Hot Code Replace (HCR) sounds magical but it does have limitations. In short, you can only change the code inside an existing function. Here are some scenarios that HCR will {0} work:", + "NOT": "NOT", + "Adding a new member function": "Adding a new member function", + "Changing the signature of an existing function": "Changing the signature of an existing function", + "Changing the value of static members (but you can do so using the VARIABLES panel when the program is paused)": "Changing the value of static members (but you can do so using the VARIABLES panel when the program is paused)", + "Referencing new classes/packages": "Referencing new classes/packages", + "Ctrl": "Ctrl", + "Ctrl + F12": "Ctrl + F12", + "⌘ F12": "⌘ F12", + "Shift + Alt + F12": "Shift + Alt + F12", + "⌥ ⇧ F12": "⌥ ⇧ F12", + "Alt + F12": "Alt + F12", + "⌥ F12": "⌥ F12", + "Shift + F12": "Shift + F12", + "⇧ F12": "⇧ F12", + "Ctrl + Shift + \\": "Ctrl + Shift + \\", + "Ctrl + Space": "Ctrl + Space", + "⌃ Space": "⌃ Space", + "Ctrl + Shift + R": "Ctrl + Shift + R", + "⌃ ⇧ R": "⌃ ⇧ R", + "Ctrl + .": "Ctrl + .", + "VS Code Java is backed by a full Java language server and it understands Java code. Because of that, you get features like Code Navigation, IntelliSense, Refactoring, etc. This is important when your projects get bigger and more complex. Now let's further look at the code editing experience.": "VS Code Java is backed by a full Java language server and it understands Java code. Because of that, you get features like Code Navigation, IntelliSense, Refactoring, etc. This is important when your projects get bigger and more complex. Now let's further look at the code editing experience.", + "Basic Editing User Guide": "Basic Editing User Guide", + "To make the most of VS Code, we strongly recommend reading the {0} user guide. You'll get to know cool tricks about multi-select, formatting, indentation, folding, and much more.": "To make the most of VS Code, we strongly recommend reading the {0} user guide. You'll get to know cool tricks about multi-select, formatting, indentation, folding, and much more.", + "Basic Editing": "Basic Editing", + "Code Navigation": "Code Navigation", + "Code Navigation makes it easy to understand existing codebase. Here to mention a few features that can help you navigate your code repositories.": "Code Navigation makes it easy to understand existing codebase. Here to mention a few features that can help you navigate your code repositories.", + "Go to Definition": "Go to Definition", + "{0}{1}You can also hover on the symbol to preview its declaration and javadoc. To jump to the definition, hold the {2} key, and click on the symbol.": "{0}{1}You can also hover on the symbol to preview its declaration and javadoc. To jump to the definition, hold the {2} key, and click on the symbol.", + "F12": "F12", + "Go to Implementation": "Go to Implementation", + "{0}{1}For an interface, this shows all the implementors of that interface and for abstract methods, this shows all concrete implementations of that method.": "{0}{1}For an interface, this shows all the implementors of that interface and for abstract methods, this shows all concrete implementations of that method.", + "Go to Type Definition": "Go to Type Definition", + "This one allows you to go to the definition of the type of the symbol. For example, you have a class member {0}, \"Go to Definition\" will take you to the definition of {1} while \"Go to {2} Definition\" will take you to the definition of {3}.": "This one allows you to go to the definition of the type of the symbol. For example, you have a class member {0}, \"Go to Definition\" will take you to the definition of {1} while \"Go to {2} Definition\" will take you to the definition of {3}.", + "Find All References": "Find All References", + "{0}{1}This allows you to quickly analyze the impact of your edit or the popularity of your specific method or property throughout your repository.": "{0}{1}This allows you to quickly analyze the impact of your edit or the popularity of your specific method or property throughout your repository.", + "The commands above will possibly take you to another file. But you can choose to stay using the peeking features below:": "The commands above will possibly take you to another file. But you can choose to stay using the peeking features below:", + "Peek Definition": "Peek Definition", + "Peek References": "Peek References", + " Last but not least, you can jump between the matching brackets back and forth: ": " Last but not least, you can jump between the matching brackets back and forth: ", + "Go to Bracket": "Go to Bracket", + "IntelliSense": "IntelliSense", + "IntelliSense is a general term for a variety of code editing features including: code completion, parameter info, quick info, and member lists. IntelliSense features are sometimes called by other names such as \"code completion\", \"content assist\", and \"code hinting.\"": "IntelliSense is a general term for a variety of code editing features including: code completion, parameter info, quick info, and member lists. IntelliSense features are sometimes called by other names such as \"code completion\", \"content assist\", and \"code hinting.\"", + "IntelliSense works as you type. For example, when you try to invoke some member of an object, a list of all the members is popped up for you to choose from. If you continue typing characters, the list of members (variables, methods, etc.) is filtered to only include members containing your typed characters. Pressing {0} or {1} will insert the selected member.": "IntelliSense works as you type. For example, when you try to invoke some member of an object, a list of all the members is popped up for you to choose from. If you continue typing characters, the list of members (variables, methods, etc.) is filtered to only include members containing your typed characters. Pressing {0} or {1} will insert the selected member.", + "Tab": "Tab", + "Enter": "Enter", + "Trigger IntelliSense Manually": "Trigger IntelliSense Manually", + "In most cases, IntelliSense is triggered automatically. You can also press {0} to do it manually. For example, when you're trying to invoke a member function and want to see the parameter info, this will do the magic.": "In most cases, IntelliSense is triggered automatically. You can also press {0} to do it manually. For example, when you're trying to invoke a member function and want to see the parameter info, this will do the magic.", + "Refactoring": "Refactoring", + "VS Code Java provides essential refactoring features and makes it productive to modify larger codebase. The most frequently used one is {0}. It's so popular that a dedicated hot key {1} is assigned to it. When you rename a symbol, all its references are also renamed.": "VS Code Java provides essential refactoring features and makes it productive to modify larger codebase. The most frequently used one is {0}. It's so popular that a dedicated hot key {1} is assigned to it. When you rename a symbol, all its references are also renamed.", + "Rename": "Rename", + "F2": "F2", + "There are more refactoring features like {0}, {1}, etc. The availability changes corresponding to the current cursor position. All available features are packed in to the {2} context menu. And you can also pop the list by pressing {3}": "There are more refactoring features like {0}, {1}, etc. The availability changes corresponding to the current cursor position. All available features are packed in to the {2} context menu. And you can also pop the list by pressing {3}", + "Extract": "Extract", + "Inline": "Inline", + "Refactor": "Refactor", + "You may also notice the lightbulb near the cursor. It indicates that some {0} are available. In VS Code, Code Actions can provide both refactorings and Quick Fixes for detected issues. To show the full list of available actions, click the lightbulb or press {1}": "You may also notice the lightbulb near the cursor. It indicates that some {0} are available. In VS Code, Code Actions can provide both refactorings and Quick Fixes for detected issues. To show the full list of available actions, click the lightbulb or press {1}", + "Code Actions": "Code Actions", + "More Code Actions": "More Code Actions", + "There are other code actions that are not limited to the cursor position. They are grouped into the {0} context menu. Here's a list of them.": "There are other code actions that are not limited to the cursor position. They are grouped into the {0} context menu. Here's a list of them.", + "Source Action": "Source Action", + "Organize Imports": "Organize Imports", + "Override/Implement Methods": "Override/Implement Methods", + "Generate Getter and Setter": "Generate Getter and Setter", + "Generate hashCode() and equals()": "Generate hashCode() and equals()", + "Generate toString()": "Generate toString()", + "Generate Constructors": "Generate Constructors", + "Generate Delegate Methods": "Generate Delegate Methods" +} \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json new file mode 100644 index 00000000..df193949 --- /dev/null +++ b/l10n/bundle.l10n.zh-cn.json @@ -0,0 +1,589 @@ +{ + "Java Help Center": "Java 帮助中心", + "Install": "安装", + "Configure classpath": "配置类路径", + "Project Settings": "项目设置", + "The required extension 'redhat.java' is not installed.": "未安装必需的扩展“redhat.java”。", + "Select Source Folder": "选择源文件夹", + "The source path must be contained in the project root folder.": "源路径必须位于项目根文件夹中。", + "The path {0} has already been a source path.": "路径 {0} 已经是源路径。", + "Open Log Files": "打开日志文件", + "Failed to update classpaths: {0}": "无法更新类路径:{0}", + "Select Output Folder": "选择输出文件夹", + "The customized output path must be contained in the project root folder.": "自定义输出路径必须位于项目根文件夹中。", + "Cannot set the project root path as the output path.": "不能将项目根路径设置为输出路径。", + "Yes": "是", + "No": "否", + "The contents in {0} will be removed, are you sure to continue?": "将删除 {0} 中的内容,确定要继续吗?", + "Select JDK Home": "选择 JDK 主目录", + "Select the installation path of the JDK": "选择 JDK 的安装路径", + "Unable to update the project JDK: {0}": "无法更新项目 JDK:{0}", + "Select Jar File": "选择 JAR 文件", + "Jar": "JAR", + "The configuration file: '{0}' does not exist.": "配置文件“{0}”不存在。", + "Unable to load Java runtimes: {0}": "无法加载 Java 运行时:{0}", + "Java Overview": "Java 概述", + "Configure Java Runtime": "配置 Java 运行时", + "Specify Java runtime to launch Language Server": "指定用于启动语言服务器的 Java 运行时", + "{0} is not a valid JDK home directory.": "{0} 不是有效的 JDK 主目录。", + "Java {0} or more recent is required to launch the Java Language Server. \"{1}\" doesn't meet the requirement.": "启动 Java 语言服务器需要 Java {0} 或更高版本。“{1}”不满足此要求。", + "Unable to refresh Configure Java Runtime: {0}": "无法刷新“配置 Java 运行时”:{0}", + "Unable to list installed project JDKs": "无法列出已安装的项目 JDK", + "Unable to read runtime information for project \"{0}\" ({1})": "无法读取项目“{0}”({1})的运行时信息", + "Unable to list projects from Project Manager for workspace \"{0}\"": "无法通过项目管理器列出工作区“{0}”中的项目", + "Unable to list projects from the Java language server": "无法通过 Java 语言服务器列出项目", + "Language Support for Java (redhat.java) is unavailable. Check that it is installed and enabled.": "Language Support for Java(redhat.java)不可用。请检查是否已安装并启用该扩展。", + "redhat.java reports an error. Open the Java logs for details.": "redhat.java 报告了错误。请打开 Java 日志查看详细信息。", + "The runtime reported by redhat.java uses Java {0}, below the required Java {1}. Open the Java logs for details.": "redhat.java 报告的运行时使用 Java {0},低于要求的 Java {1}。请打开 Java 日志查看详细信息。", + "The configured 'java.jdt.ls.java.home' uses Java {0}, below the required Java {1}. redhat.java reports a different language-server runtime.": "配置的“java.jdt.ls.java.home”使用 Java {0},低于要求的 Java {1}。redhat.java 报告了不同的语言服务器运行时。", + "The configured 'java.jdt.ls.java.home' differs from the runtime reported by redhat.java. Open the Java logs for details.": "配置的“java.jdt.ls.java.home”与 redhat.java 报告的运行时不同。请打开 Java 日志查看详细信息。", + "Install New JDK": "安装新 JDK", + "The setting has no valid 'id' property.": "该设置没有有效的“id”属性。", + "The setting has no valid 'value' property.": "该设置没有有效的“value”属性。", + "\"{0}\" is not supported in id: \"{1}\".": "ID“{1}”不支持“{0}”。", + "Retry": "重试", + "Open Settings": "打开设置", + "Failed to get the profile content from uri: {0}. Do you want to retry?": "无法从 URI {0} 获取配置文件内容。是否重试?", + "The active formatter profile does not exist or is not remote, please check it in the Settings and try again.": "当前格式化程序配置文件不存在或不是远程文件,请在设置中检查后重试。", + "The extension 'redhat.java' is not installed. Please install it and run this command again.": "未安装扩展“redhat.java”。请安装该扩展后重新运行此命令。", + "The extension version of 'redhat.java' is too stale. Please install at least {0} and run this command again.": "扩展“redhat.java”的版本过旧。请安装 {0} 或更高版本后重新运行此命令。", + "The current profile is invalid, please check it in the Settings and try again.": "当前配置文件无效,请在设置中检查后重试。", + "Formatter Profile settings have been changed, do you want to reload this editor?": "格式化程序配置文件设置已更改,是否重新加载此编辑器?", + "No active Formatter Profile found, do you want to create a default one?": "未找到当前格式化程序配置文件,是否创建默认配置文件?", + "Open in read-only mode": "以只读模式打开", + "Download and use it locally": "下载并在本地使用", + "The active formatter profile is remote, do you want to open it in read-only mode or download and use it locally?": "当前格式化程序配置文件是远程文件,要以只读模式打开,还是下载并在本地使用?", + "Generate a default profile": "生成默认配置文件", + "The active formatter profile does not exist, please check it in the Settings and try again.": "当前格式化程序配置文件不存在,请在设置中检查后重试。", + "Java Extensions Guide": "Java 扩展指南", + "Clean and Restart": "清理并重启", + "Java extension cannot start due to corrupted workspace cache, please try to clean the workspace.": "工作区缓存已损坏,Java 扩展无法启动,请尝试清理工作区。", + "Maven extension is recommended to help create Java projects and work with custom goals.": "建议安装 Maven 扩展,以帮助创建 Java 项目和使用自定义目标。", + "Spring Initializr extension is recommended to help create Spring Boot projects and manage dependencies.": "建议安装 Spring Initializr 扩展,以帮助创建 Spring Boot 项目和管理依赖项。", + "Quarkus Tools for Visual Studio Code is recommended to help create Quarkus projects and for an all-in-one Quarkus application development experience.": "建议安装 Quarkus Tools for Visual Studio Code,以帮助创建 Quarkus 项目并获得一站式 Quarkus 应用程序开发体验。", + "MicroProfile Starter for Visual Studio Code is recommended to generate starter projects for Eclipse MicroProfile.": "建议安装 MicroProfile Starter for Visual Studio Code,以生成 Eclipse MicroProfile 起始项目。", + "Installing {0}...": "正在安装 {0}...", + "Successfully installed {0}.": "已成功安装 {0}。", + "Unable to update Java AWT development settings: {0}": "无法更新 Java AWT 开发设置:{0}", + "Java AWT development is enabled.": "已启用 Java AWT 开发。", + "Java AWT development is disabled.": "已禁用 Java AWT 开发。", + "Tips for Beginners": "新手提示", + "XML extension is recommended to check the syntax when editing pom.xml.": "建议安装 XML 扩展,以在编辑 pom.xml 时检查语法。", + "Open Project Folder": "打开项目文件夹", + "{0} containing your Java project for full features.": "{0}以使用 Java 项目的完整功能。", + "Open a folder": "打开文件夹", + "Project Explorer": "项目资源管理器", + "Expand {0} to view your project structure.": "展开{0}以查看项目结构。", + "Java Project Explorer": "Java 项目资源管理器", + "Running and Debugging": "运行和调试", + "Open {0} to start your project.": "打开{0}以启动项目。", + "Run and Debug View": "运行和调试视图", + "Testing": "测试", + "Use {0} to run unit tests.": "使用{0}运行单元测试。", + "Testing View": "测试视图", + "logo": "徽标", + "Welcome to use Java Tools": "欢迎使用 Java 工具", + "lightweight, performant, powerful.": "轻量、高效、强大。", + "Get Started": "开始使用", + "skip": "跳过", + "Next Step": "下一步", + "You're good to go!": "一切准备就绪!", + "Next, start using Java!": "接下来,开始使用 Java!", + "What's next?": "下一步做什么?", + "Loading...": "正在加载...", + "Create a {0}": "创建{0}", + "New Project": "新项目", + "Open an {0}": "打开{0}", + "Existing Project": "现有项目", + "Take a {0}": "查看{0}", + "Tour": "导览", + "General": "常规", + "Open Java Settings": "打开 Java 设置", + "Install Extensions...": "安装扩展...", + "Configure Formatter Settings": "配置格式化程序设置", + "Spring": "Spring", + "Spring Boot with VS Code": "在 VS Code 中使用 Spring Boot", + "Spring PetClinic Sample Application": "Spring PetClinic 示例应用程序", + "Install Spring Boot Extension Pack ...": "安装 Spring Boot Extension Pack ...", + "Student": "学生", + "Coding and Debugging Tips": "编码和调试提示", + "Tutorial: Running and Debugging": "教程:运行和调试", + "Tutorial: Testing": "教程:测试", + "Configure Sources, Dependencies, Output Folder...": "配置源代码、依赖项和输出文件夹...", + "Quick Start: Jupyter Notebook for Java": "快速入门:用于 Java 的 Jupyter Notebook", + "Enable AWT Development": "启用 AWT 开发", + "Disable AWT Development": "禁用 AWT 开发", + "blogs": "博客", + "Check our {0} to see what's new": "查看我们的{0}以了解最新动态", + "{0} Show Help Center when using Java": "{0} 使用 Java 时显示帮助中心", + "Not a Maven project": "不是 Maven 项目", + "Active Maven Profiles": "活动 Maven 配置文件", + "(comma separated)": "(用逗号分隔)", + "Classpath": "类路径", + "Compiler": "编译器", + "Maven": "Maven", + "Formatter {0}": "格式化程序 {0}", + "Project:": "项目:", + "Applying...": "正在应用...", + "Apply Settings": "应用设置", + "There are no Java projects opened in the current workspace. Please try to {0} or {1}.": "当前工作区中未打开任何 Java 项目。请尝试{0}或{1}。", + "reload the page": "重新加载页面", + "open a Java project": "打开 Java 项目", + "The required extension {0} is not installed or it's disabled. Please {1} it in Visual Studio Code and {2} the page after installation.": "必需的扩展 {0} 未安装或已禁用。请在 Visual Studio Code 中{1}该扩展,安装后{2}页面。", + "Language Support for Java™ by Red Hat": "Language Support for Java™ by Red Hat", + "install": "安装", + "reload": "重新加载", + "The version of required extension {0} is too stale. Please {1} it and {2} the page.": "必需的扩展 {0} 版本过旧。请{1}该扩展并{2}页面。", + "update": "更新", + "Use '--release' option for cross-compilation (Java 9 and later)": "使用“--release”选项进行交叉编译(Java 9 及更高版本)", + "Bytecode version:": "字节码版本:", + "Source compatibility:": "源兼容性:", + "Target compatibility:": "目标兼容性:", + "Target compatibility must be equal or greater than source compatibility.": "目标兼容性版本必须等于或高于源兼容性版本。", + "Please make sure to have a compatible JDK configured (currently {0}). You can change the JDK under the {1} tab.": "请确保已配置兼容的 JDK(当前为 {0})。可以在{1}选项卡下更改 JDK。", + "JDK Runtime": "JDK 运行时", + "Enable preview features": "启用预览功能", + "Class File Generation": "类文件生成", + "Generate debugging information": "生成调试信息", + "Store information about method parameters": "存储方法参数信息", + "'{0}' is imported by {1}, some changes made to the compiler settings might be lost after reloading. To make permanent changes, please edit the {2} file.": "“{0}”由 {1} 导入,对编译器设置的部分更改可能会在重新加载后丢失。若要永久更改,请编辑 {2} 文件。", + "Sources": "源代码", + "Libraries": "库", + "No source paths are configured.": "未配置源路径。", + "Remove": "删除", + "Source Paths": "源路径", + "{0}Add Source Root...": "{0}添加源根目录...", + "Source Path:": "源路径:", + "Source Root Path": "源根路径", + "Browse...": "浏览...", + "Output Path:": "输出路径:", + "Output Path": "输出路径", + "OK": "确定", + "Cancel": "取消", + "Edit": "编辑", + "Path": "路径", + "Output": "输出", + "No libraries are configured.": "未配置库。", + "{0}Add Library...": "{0}添加库...", + "JDK:": "JDK:", + "Current project JDK (not listed)": "当前项目 JDK(不在列表中)", + "Project JDK not available": "项目 JDK 不可用", + "The current project JDK is not in the available runtime list. Refresh JDKs or locate its installation.": "当前项目 JDK 不在可用运行时列表中。请刷新 JDK 列表或查找其安装位置。", + "{0}Refresh JDKs": "{0}刷新 JDK", + "{0}Find a local JDK...": "{0}查找本地 JDK...", + "{0}Download a new JDK...": "{0}下载新 JDK...", + "'{0}' is imported by {1}, changes made to the classpath might be lost after reloading. To make permanent changes, please edit the {2} file.": "“{0}”由 {1} 导入,对类路径的更改可能会在重新加载后丢失。若要永久更改,请编辑 {2} 文件。", + "Start": "开始", + "Create a Maven project using archetypes": "使用原型创建 Maven 项目", + "Create a Maven project...": "创建 Maven 项目...", + "Create a project with Spring Initializr": "使用 Spring Initializr 创建项目", + "Create a Spring Boot project...": "创建 Spring Boot 项目...", + "Create a project with Quarkus Tools for Visual Studio Code": "使用 Quarkus Tools for Visual Studio Code 创建项目", + "Create a Quarkus project...": "创建 Quarkus 项目...", + "Create a project with MicroProfile Starter for Visual Studio Code": "使用 MicroProfile Starter for Visual Studio Code 创建项目", + "Create a MicroProfile project...": "创建 MicroProfile 项目...", + "Key Bindings": "键绑定", + "Use IntelliJ IDEA hot keys in VS Code...": "在 VS Code 中使用 IntelliJ IDEA 快捷键...", + "Use IntelliJ IDEA Key Bindings": "使用 IntelliJ IDEA 键绑定", + "Use Eclipse hot keys in VS Code...": "在 VS Code 中使用 Eclipse 快捷键...", + "Use Eclipse Key Bindings": "使用 Eclipse 键绑定", + "Extensions": "扩展", + "Install the Java language support extension...": "安装 Java 语言支持扩展...", + "Install Language Support for Java by Red Hat": "安装 Language Support for Java by Red Hat", + "Install the Debugger for Java extension...": "安装 Debugger for Java 扩展...", + "Install Debugger for Java": "安装 Debugger for Java", + "Install the Java Test Runner extension...": "安装 Java Test Runner 扩展...", + "Install Java Test Runner": "安装 Java Test Runner", + "Install the Maven for Java extension...": "安装 Maven for Java 扩展...", + "Install Maven for Java": "安装 Maven for Java", + "Install SonarLint...": "安装 SonarLint...", + "Install SonarLint": "安装 SonarLint", + "Install the Tomcat for Java extension...": "安装 Tomcat for Java 扩展...", + "Install Tomcat for Java": "安装 Tomcat for Java", + "Install the Checkstyle for Java extension...": "安装 Checkstyle for Java 扩展...", + "Install Checkstyle for Java": "安装 Checkstyle for Java", + "Schema validation when editing pom.xml...": "编辑 pom.xml 时验证架构...", + "Install XML extension": "安装 XML 扩展", + "Install the Project Manager for Java extension...": "安装 Project Manager for Java 扩展...", + "Install Project Manager for Java": "安装 Project Manager for Java", + "Learn how to work with Spring Boot projects in VS Code": "了解如何在 VS Code 中使用 Spring Boot 项目", + "Run PetClinic sample app in VS Code": "在 VS Code 中运行 PetClinic 示例应用程序", + "Install Spring Boot Extension Pack...": "安装 Spring Boot Extension Pack...", + "Install Spring Boot Extension Pack": "安装 Spring Boot Extension Pack", + "Microservices": "微服务", + "Learn how to work with Kubernetes in VS Code": "了解如何在 VS Code 中使用 Kubernetes", + "Kubernetes in VS Code": "在 VS Code 中使用 Kubernetes", + "Learn how to work with Docker in VS Code": "了解如何在 VS Code 中使用 Docker", + "Docker in VS Code": "在 VS Code 中使用 Docker", + "Marketplace link for Extension Pack for MicroProfile": "Extension Pack for MicroProfile 的扩展市场链接", + "Extension Pack for MicroProfile in VS Code": "VS Code 中的 Extension Pack for MicroProfile", + "Marketplace link for Quarkus Tools for VS Code": "Quarkus Tools for VS Code 的扩展市场链接", + "Quarkus Tools for VS Code": "Quarkus Tools for VS Code", + "Install Kubernetes extension...": "安装 Kubernetes 扩展...", + "Install Kubernetes Extension": "安装 Kubernetes 扩展", + "Install Docker extension...": "安装 Docker 扩展...", + "Install Docker Extension": "安装 Docker 扩展", + "Install Extension Pack for MicroProfile...": "安装 Extension Pack for MicroProfile...", + "Install Extension Pack for MicroProfile": "安装 Extension Pack for MicroProfile", + "Install Quarkus extension...": "安装 Quarkus 扩展...", + "Install Quarkus Extension": "安装 Quarkus 扩展", + "Help": "帮助", + "Report issues or request features": "报告问题或请求功能", + "Questions & Issues": "疑问和问题", + "Tweet us your feedback": "通过 Twitter 向我们反馈", + "Twitter": "Twitter", + "Learn": "学习", + "Open Java Beginner Tips View": "打开 Java 新手提示视图", + "Java Beginner Tips": "Java 新手提示", + "Learn 1 min {0} tutorial, common shortcuts for {1} and {2}, and {3}.": "学习一分钟{0}教程、{1}和{2}的常用快捷键,以及{3}。", + "Quick Start": "快速入门", + "Code Editing": "代码编辑", + "Debugging": "调试", + "FAQ": "常见问题", + "Open Java Tutorials": "打开 Java 教程", + "Java Tutorials": "Java 教程", + "Learn how to {0} and {1} in VS Code.": "了解如何在 VS Code 中{0}和{1}。", + "Open Java Debugging Tutorial": "打开 Java 调试教程", + "debug Java apps": "调试 Java 应用程序", + "Open Java Testing Tutorial": "打开 Java 测试教程", + "run JUnit tests": "运行 JUnit 测试", + "Configuration": "配置", + "Open Java Runtime Guide": "打开 Java 运行时指南", + "Setup JDKs for projects and VS Code Java.": "为项目和 VS Code Java 设置 JDK。", + "Open Extensions Guide": "打开扩展指南", + "Extensions Guide": "扩展指南", + "Recommended extensions for Java development.": "推荐用于 Java 开发的扩展。", + "Java Settings": "Java 设置", + "Show the Java settings.": "显示 Java 设置。", + "Show overview page when using Java": "使用 Java 时显示概述页面", + "Default project": "默认项目", + "Unmanaged folder": "非托管文件夹", + "Gradle": "Gradle", + "Others": "其他", + "Configure Runtime for Language Server": "配置语言服务器运行时", + "{0}Java Language Server requires a JDK {1}+ to launch itself. Your projects can use older JDKs.": "{0}Java 语言服务器需要 JDK {1} 或更高版本才能启动。项目可以使用较早版本的 JDK。", + "Language server runtime reported by redhat.java: {0} (Java {1}).": "redhat.java 报告的语言服务器运行时:{0}(Java {1})。", + "Language server runtime information has not been reported by redhat.java.": "redhat.java 尚未报告语言服务器运行时信息。", + "{0} for details. Runtime selection and startup diagnostics are provided by redhat.java.": "{0}以了解详细信息。运行时选择和启动诊断由 redhat.java 提供。", + "Open Java Logs": "打开 Java 日志", + "Refresh{0}": "刷新{0}", + "For projects managed by build tools, Java version is specified in build scripts(e.g. pom.xml).": "对于由构建工具管理的项目,Java 版本在构建脚本(如 pom.xml)中指定。", + "For projects managed by build tools, Java version is specified in build scripts(e.g. build.gradle).": "对于由构建工具管理的项目,Java 版本在构建脚本(如 build.gradle)中指定。", + "For folders containing .java files, but not managed by build tools like Maven/Gradle, a default JDK is used.": "对于包含 .java 文件但未由 Maven/Gradle 等构建工具管理的文件夹,将使用默认 JDK。", + "Configure Runtime for Projects": "配置项目运行时", + "Language server runtime information is not available yet. Use Refresh after redhat.java starts, or {0} for details.": "语言服务器运行时信息尚不可用。请在 redhat.java 启动后刷新,或{0}以了解详细信息。", + "open the Java logs": "打开 Java 日志", + "JDK {0}+ is required for the language server only; your projects can use older JDKs. {1}.": "只有语言服务器需要 JDK {0} 或更高版本;项目可以使用较早版本的 JDK。{1}。", + "Open language-server runtime settings": "打开语言服务器运行时设置", + "Manage Java runtime for your projects. If you don't have a valid Java runtime, you can {0} one.": "管理项目的 Java 运行时。如果没有有效的 Java 运行时,可以{0}一个。", + "download": "下载", + "Project Name": "项目名称", + "Type": "类型", + "Java Version": "Java 版本", + "Project information could not be fully loaded. Please refresh to try again.": "无法完整加载项目信息。请刷新后重试。", + "No project detected yet. Please refresh later if Java extension is importing your projects.": "尚未检测到项目。如果 Java 扩展正在导入项目,请稍后刷新。", + "Locate an {0}": "查找{0}", + "Existing JDK": "现有 JDK", + "Reload": "重新加载", + "Install a {0}": "安装{0}", + "New JDK": "新 JDK", + "You need to enable JavaScript to run this app.": "需要启用 JavaScript 才能运行此应用程序。", + "Adoptium's Temurin": "Adoptium's Temurin", + "After you finish JDK installation, please reload Visual Studio Code to make it effective.": "安装 JDK 后,请重新加载 Visual Studio Code 以使其生效。", + "Reload Window": "重新加载窗口", + "Having trouble?": "遇到问题?", + " (LTS)": "(LTS)", + "Download": "下载", + "Version": "版本", + "JVM": "JVM", + "hotspot": "hotspot", + "Java Formatter Settings": "Java 格式化程序设置", + "Indentation policy": "缩进策略", + "Tab size": "制表符大小", + "Detect indentation from file content": "从文件内容检测缩进", + "In control statements": "在控制语句中", + "Before 'while' in a 'do' statement": "在“do”语句的“while”之前", + "Before 'finally' in a 'try' statement": "在“try”语句的“finally”之前", + "Before 'else' in an 'if' statement": "在“if”语句的“else”之前", + "Before 'catch' in a 'try' statement": "在“try”语句的“catch”之前", + "Before closing brace in array initializer": "在数组初始值设定项的右大括号之前", + "After opening brace in array initializer": "在数组初始值设定项的左大括号之后", + "After annotation": "在注解之后", + "After annotation on parameters": "在参数的注解之后", + "After annotation on packages": "在包的注解之后", + "After annotation on enum constants": "在枚举常量的注解之后", + "Before empty statement": "在空语句之前", + "In empty class declaration": "在空类声明中", + "Reserve line for class declaration": "为类声明保留行", + "Reserve line for record declaration": "为记录声明保留行", + "Reserve line for record constructor": "为记录构造函数保留行", + "In empty method body": "在空方法体中", + "Reserve line for method body": "为方法体保留行", + "In empty enum declaration": "在空枚举声明中", + "Reserve line for enum declaration": "为枚举声明保留行", + "In empty enum constant": "在空枚举常量中", + "Reserve line for enum constant declaration": "为枚举常量声明保留行", + "In empty anonymous type declaration": "在空匿名类型声明中", + "Reserve line for anonymous type declaration": "为匿名类型声明保留行", + "In empty annotation declaration": "在空注解声明中", + "Reserve line for annotation declaration": "为注解声明保留行", + "Between class declarations": "在类声明之间", + "Between import groups": "在导入组之间", + "Before package declarations": "在包声明之前", + "Before import declarations": "在导入声明之前", + "Between member type declarations": "在成员类型声明之间", + "Empty lines to preserve": "要保留的空行数", + "Maximum line width": "最大行宽", + "Maximum comment line length": "最大注释行长度", + "Indent wrapped parameter description": "缩进换行后的参数说明", + "Enable header comment formatting": "启用文件头注释格式化", + "Enable comment formatting": "启用注释格式化", + "Enable block comment formatting": "启用块注释格式化", + "Enable line comment formatting": "启用行注释格式化", + "Count line length from starting position": "从起始位置计算行长度", + "Remove blank lines in comment": "删除注释中的空行", + "Remove blank lines in Javadoc": "删除 Javadoc 中的空行", + "Remove blank lines in block comment": "删除块注释中的空行", + "Use On/Off tags": "使用启用/禁用标记", + "Before first initializer": "在第一个初始值设定项之前", + "After closing parenthesis in cast": "在类型转换的右括号之后", + "After closing angle bracket in type": "在类型的右尖括号之后", + "tab": "制表符", + "space": "空格", + "never": "从不", + "if empty": "为空时", + "if at most one item": "最多包含一项时", + "Indentation": "缩进", + "Blank line": "空行", + "Comment": "注释", + "Insert Line": "插入行", + "Braced type": "类型大括号", + "Braced record": "记录大括号", + "Braced enum": "枚举大括号", + "Annotation and anonymous": "注解和匿名类型", + "Whitespace": "空白", + "Wrapping": "换行", + "Blank Lines": "空行", + "Java Formatter Settings (Read Only)": "Java 格式化程序设置(只读)", + "Download and edit profile": "下载并编辑配置文件", + "Download and Edit": "下载并编辑", + "When enabled, the indentation settings will be overriden based on the file contents.": "启用后,将根据文件内容覆盖缩进设置。", + "Basics": "基础", + "Frameworks": "框架", + "Application Servers": "应用程序服务器", + "Keymaps": "键映射", + "Language Support for Java by Red Hat": "Language Support for Java by Red Hat", + "Debugger for Java": "Debugger for Java", + "Project Manager for Java": "Project Manager for Java", + "Test Runner for Java": "Test Runner for Java", + "Maven for Java": "Maven for Java", + "SonarLint": "SonarLint", + "Spring Boot Extension Pack": "Spring Boot Extension Pack", + "Extension Pack for MicroProfile": "Extension Pack for MicroProfile", + "Quarkus": "Quarkus", + "Community Server Connectors": "Community Server Connectors", + "Eclipse Keymap": "Eclipse Keymap", + "IntelliJ IDEA Keybindings": "IntelliJ IDEA Keybindings", + "Java Linting, Intellisense, formatting, refactoring, Maven/Gradle support and more.": "Java 代码检查、IntelliSense、格式化、重构、Maven/Gradle 支持等功能。", + "Debug Java applications.": "调试 Java 应用程序。", + "Manage Java projects, dependencies, and generate packages.": "管理 Java 项目和依赖项,以及生成包。", + "Run and debug JUnit & TestNG test cases.": "运行和调试 JUnit 与 TestNG 测试用例。", + "Manage Maven projects, work with goals & dependencies, generate projects from archetypes.": "管理 Maven 项目、使用目标和依赖项,以及通过原型生成项目。", + "Detect and fix quality issues as you write code.": "在编写代码时检测和修复质量问题。", + "Spring Boot-specific support for \".java\" files. As well as validation and content assist for Spring Boot \"application.properties\", \"application.yml\" properties files.": "为“.java”文件提供 Spring Boot 专用支持,同时为 Spring Boot 的“application.properties”和“application.yml”属性文件提供验证和内容辅助。", + "A collection of extensions to develop Java microservices with Eclipse MicroProfile": "一组用于通过 Eclipse MicroProfile 开发 Java 微服务的扩展", + "Quarkus Tools for Visual Studio Code.": "Quarkus Tools for Visual Studio Code。", + "Manage and publish to servers and runtimes like Tomcat, Apache Felix, and Karaf.": "管理 Tomcat、Apache Felix 和 Karaf 等服务器及运行时,并向其发布应用程序。", + "Port of Eclipse keyboard shortcuts.": "将 Eclipse 键盘快捷键移植到 VS Code。", + "Port of IntelliJ IDEA Keybindings, including for WebStorm, PyCharm, PHP Storm, etc.": "移植 IntelliJ IDEA 键绑定,包括 WebStorm、PyCharm、PHP Storm 等产品的键绑定。", + "Learn More": "了解详细信息", + "Install Selected": "安装所选扩展", + "Install All": "安装全部扩展", + "Install Selected ({0})": "安装所选扩展({0})", + "Feedback Channels": "反馈渠道", + "VS Code Java is new, and we are here to help.": "VS Code Java 是新工具,我们随时提供帮助。", + "Ask Questions": "提出问题", + "{0} Gitter channel is recommended to ask for help": "建议通过 {0} Gitter 频道寻求帮助", + "vscode-java": "vscode-java", + "Open Issues": "提交问题", + "{0} GitHub repo is recommended for opening bugs": "建议在 {0} GitHub 仓库中报告缺陷", + "vscode-java-pack": "vscode-java-pack", + "Other Feedback": "其他反馈", + "{0} is the handle to mention on twitter": "在 Twitter 上反馈时请提及 {0}", + "@VSCodeJava": "@VSCodeJava", + "Why do I see the JDK errors?": "为什么会看到 JDK 错误?", + "{0} to run the installed Java language support (redhat.java) extension. A compatible bundled runtime can satisfy this requirement; otherwise, a compatible local JDK is needed. To set the language-server launch JDK explicitly, configure {1}. Runtime selection and startup diagnostics are provided by redhat.java; {2} for details.": "运行已安装的 Java 语言支持扩展(redhat.java)时,{0}。兼容的捆绑运行时可以满足此要求;否则,需要兼容的本地 JDK。若要显式设置启动语言服务器的 JDK,请配置 {1}。运行时选择和启动诊断由 redhat.java 提供;{2}以了解详细信息。", + "{0} is required": "需要 {0}", + "The {0} page configures project JDKs, not the language-server launch JDK. Your projects can use older JDKs independently of the tooling requirement.": "{0}页面用于配置项目 JDK,而非启动语言服务器的 JDK。项目可以使用较早版本的 JDK,不受工具运行时要求的限制。", + "Can I run my Java 8 project with JDK 1.8?": "能否使用 JDK 1.8 运行 Java 8 项目?", + "Yes. The JDK {0} requirement is just for running the Java language support (redhat.java) extension itself. You can still configure a different runtime {1} via the user setting {2}. The extension will pick a matching JDK to compile/run your project according to the compiler version specified by the project build file.": "可以。JDK {0} 的要求仅适用于运行 Java 语言支持扩展(redhat.java)本身。仍可通过用户设置 {2} 为{1}配置不同的运行时。扩展将根据项目构建文件中指定的编译器版本,选择匹配的 JDK 来编译和运行项目。", + "JDK for your project": "项目 JDK", + "Why do I see tons of problems and red squiggles?": "为什么会看到大量问题和红色波浪线?", + "The problems are from VS Code Java when it tries to compile and build your codebase. If you experience this on your first use, it's possibly because of {0}. To fix it, you probably want to start from fixing the project configuration files, e.g. {1} and {2}. After you make changes to those files, try {3} and {4}.": "这些问题来自 VS Code Java 编译和构建代码库的过程。如果首次使用时遇到此情况,可能是因为{0}。若要修复,请先检查项目配置文件,例如 {1} 和 {2}。更改这些文件后,请尝试{3}和{4}。", + "missing dependencies": "缺少依赖项", + "Update Project Configuration": "更新项目配置", + "Force Compilation": "强制编译", + "It can also happen after you work with one project for a while. Try {0} to get rid of any intermediate output from the language server.": "使用项目一段时间后也可能出现此情况。请尝试{0},以清除语言服务器的中间输出。", + "Clean Workspace": "清理工作区", + "If the problem persists, follow the {0}. For advanced users, the {1} and {2} will definitely help you understand what is going on.": "如果问题仍然存在,请按照{0}操作。对于高级用户,{1}和{2}有助于了解具体情况。", + "Troubleshooting Guide": "故障排除指南", + "Client Logs": "客户端日志", + "Server Logs": "服务器日志", + "Why can't I see any IntelliSense suggestions?": "为什么看不到任何 IntelliSense 建议?", + "VS Code Java needs to compile your code before it can provide suggestions. When it's working, you should see a spinning 🔄 on the right end of the status bar. And it will show 👍 when it's done. And you should be able to use all the features.": "VS Code Java 需要先编译代码才能提供建议。编译过程中,状态栏右侧会显示旋转的 🔄。完成后会显示 👍,此时即可使用全部功能。", + "It could take longer for the language server to load a project which references lots of dependencies. Those dependencies need to be resolved and downloaded from the internet. So the network connection plays a critical role in the process.": "语言服务器加载引用大量依赖项的项目时可能需要较长时间。这些依赖项需要解析并从互联网下载,因此网络连接在此过程中至关重要。", + "Can I use Lombok?": "能否使用 Lombok?", + "Yes. You'll need to install the {0} extension, which enables VS Code to process Lombok annotations. To learn more about alternatives and details, visit {1}.": "可以。需要安装 {0} 扩展,使 VS Code 能够处理 Lombok 注解。有关替代方案和详细信息,请访问{1}。", + "Lombok": "Lombok", + "this page": "此页面", + "Can I develop Android apps using VS Code Java?": "能否使用 VS Code Java 开发 Android 应用程序?", + "Sorry, it's not supported now.": "抱歉,目前尚不支持。", + "How to troubleshoot the problems?": "如何排查问题?", + "You could click {0} -> {1} to get the logs. Also learn more at {2}.": "可以依次点击 {0} -> {1} 获取日志。也可在{2}了解详细信息。", + "F1": "F1", + "Java: Open all log files": "Java: 打开所有日志文件", + "Ctrl + F5": "Ctrl + F5", + "⌃ F5": "⌃ F5", + "Shift + F11": "Shift + F11", + "⇧ F11": "⇧ F11", + "Ctrl + Shift + F5": "Ctrl + Shift + F5", + "⇧ ⌘ F5": "⇧ ⌘ F5", + "Shift + F5": "Shift + F5", + "⇧ F5": "⇧ F5", + "One of the key features of Visual Studio Code is its great debugging support. VS Code's built-in debugger helps accelerate your edit, compile and debug loop.": "强大的调试支持是 Visual Studio Code 的核心功能之一。VS Code 内置的调试器有助于加快编辑、编译和调试循环。", + "Start Debugging": "开始调试", + "There are multiple ways to start debugging a Java program. By pressing {0}, the current program will be launched. You can also start by clicking the {1} codelens on top of the {2} function. This is super handy when you have multiple main entries. You can also launch a program {3} debugging by pressing {4}.": "有多种方式可以开始调试 Java 程序。按 {0} 可启动当前程序,也可以点击 {2} 函数上方的 {1} CodeLens。在有多个主入口时,这种方式特别方便。还可以按 {4} 启动程序而{3}调试。", + "F5": "F5", + "\"Debug\"": "“调试”", + "without": "不进行", + "By default, VS Code Java launches the program using {0}. As you enter the debug mode, you should also see the {1}. This view shows all the runtime info of your program.": "默认情况下,VS Code Java 使用{0}启动程序。进入调试模式后,还会显示{1},其中包含程序的所有运行时信息。", + "Integrated Terminal": "集成终端", + "Debug View": "调试视图", + "Debug Configurations": "调试配置", + "VS Code Java automatically generates debug configurations. In VS Code, those configurations are called {0} and they are persisted in {1}. To work with more sophisticated debug scenarios, please explore the {2} that are supported by VS Code.": "VS Code Java 会自动生成调试配置。在 VS Code 中,这些配置称为{0},并保存在 {1} 中。对于更复杂的调试场景,请了解 VS Code 支持的{2}。", + "Launch Configurations": "启动配置", + "Launch Options": "启动选项", + "Breakpoints": "断点", + "Breakpoints can be toggled by clicking on the editor margin or using {0} on the current line. Finer breakpoint control (enable/disable/reapply) can be done in the Debug View's BREAKPOINTS section.": "点击编辑器边距或在当前行按 {0} 可切换断点。可在调试视图的“断点”部分进行更精细的控制(启用、禁用或重新应用)。", + "F9": "F9", + "You can also set {0} based on expressions, hit counts, or a combination of both.": "还可以根据表达式、命中次数或两者的组合设置{0}。", + "Conditional Breakpoints": "条件断点", + "Expression condition": "表达式条件", + "The breakpoint will be hit whenever the expression evaluates to {0}": "每当表达式的计算结果为 {0} 时,就会命中断点", + "Hit count": "命中次数", + "The 'hit count' controls how many times a breakpoint needs to be hit before it will 'break' execution": "“命中次数”控制断点需要被命中多少次后才会中断执行", + "You can add a condition and/or hit count when creating the breakpoint (with the {0} action) or when modifying an existing one (with the Edit Breakpoint action). In both cases, an inline text box with a drop-down menu opens where you can enter expressions.": "创建断点时(使用{0}操作)或修改现有断点时(使用“编辑断点”操作),可以添加条件和/或命中次数。在这两种情况下,都会打开带有下拉菜单的内联文本框,供您输入表达式。", + "Add Conditional Breakpoint": "添加条件断点", + "Logpoints": "日志点", + "A Logpoint is a variant of a breakpoint that does not \"break\" into the debugger but instead logs a message to the console. Logpoints are especially useful for injecting logging while debugging production servers that cannot be paused or stopped.": "日志点是断点的一种变体,不会中断并进入调试器,而是向控制台记录消息。调试不能暂停或停止的生产服务器时,日志点对于插入日志尤其有用。", + "A Logpoint is represented by a ♦️ shaped icon. Log messages are plain text but can include expressions to be evaluated within curly braces ('{ }').": "日志点以 ♦️ 形图标表示。日志消息为纯文本,但可以在大括号('{ }')内包含要计算的表达式。", + "Debug Actions": "调试操作", + "Once a debug session starts, the Debug toolbar will appear on the top of the editor. You can control the execution flow using the actions below.": "调试会话启动后,调试工具栏将出现在编辑器顶部。可以使用以下操作控制执行流程。", + "Continue/Pause": "继续/暂停", + "Step Over": "单步跳过", + "F10": "F10", + "Step Into": "单步调试", + "F11": "F11", + "Step Out": "单步跳出", + "Restart": "重新启动", + "Stop": "停止", + "Inspect Variables": "检查变量", + "Variables can be inspected in the {0} section of the Debug view or by hovering over their source in the editor. Variable values and expression evaluation are relative to the selected stack frame in the {1} section.": "可以在调试视图的{0}部分检查变量,也可以将鼠标悬停在编辑器中的变量上。变量值和表达式计算基于{1}部分中选中的堆栈帧。", + "VARIABLES": "变量", + "CALL STACK": "调用堆栈", + "Variable values can be modified with the {0} action from the variable's context menu. Or you can {1} the value and enter a new one. Variables and expressions can also be evaluated and watched in the Debug view's {2} section.": "可以通过变量上下文菜单中的{0}操作修改变量值,也可以{1}该值并输入新值。还可以在调试视图的{2}部分计算和监视变量及表达式。", + "Set Value": "设置值", + "double-click": "双击", + "WATCH": "监视", + "Hot Code Replace ⚡": "热代码替换 ⚡", + "Yes, you can apply code changes without restarting the running program. Click on the {0} icon in the {1} to apply code changes. When you see failures, don't worry. It is safe to continue running the program, but you may notice discrepancies between the source code and the program.": "可以在不重启运行中程序的情况下应用代码更改。点击{1}中的 {0} 图标即可应用更改。如果遇到失败,也不必担心,可以安全地继续运行程序,但源代码与程序之间可能存在差异。", + "debug toolbar": "调试工具栏", + "Limitations": "限制", + "Hot Code Replace (HCR) sounds magical but it does have limitations. In short, you can only change the code inside an existing function. Here are some scenarios that HCR will {0} work:": "热代码替换(HCR)听起来很神奇,但也存在限制。简而言之,只能更改现有函数内部的代码。以下是 HCR {0}起作用的情况:", + "NOT": "不", + "Adding a new member function": "添加新的成员函数", + "Changing the signature of an existing function": "更改现有函数的签名", + "Changing the value of static members (but you can do so using the VARIABLES panel when the program is paused)": "更改静态成员的值(但可以在程序暂停时使用“变量”面板进行更改)", + "Referencing new classes/packages": "引用新的类或包", + "Ctrl": "Ctrl", + "Ctrl + F12": "Ctrl + F12", + "⌘ F12": "⌘ F12", + "Shift + Alt + F12": "Shift + Alt + F12", + "⌥ ⇧ F12": "⌥ ⇧ F12", + "Alt + F12": "Alt + F12", + "⌥ F12": "⌥ F12", + "Shift + F12": "Shift + F12", + "⇧ F12": "⇧ F12", + "Ctrl + Shift + \\": "Ctrl + Shift + \\", + "Ctrl + Space": "Ctrl + Space", + "⌃ Space": "⌃ Space", + "Ctrl + Shift + R": "Ctrl + Shift + R", + "⌃ ⇧ R": "⌃ ⇧ R", + "Ctrl + .": "Ctrl + .", + "VS Code Java is backed by a full Java language server and it understands Java code. Because of that, you get features like Code Navigation, IntelliSense, Refactoring, etc. This is important when your projects get bigger and more complex. Now let's further look at the code editing experience.": "VS Code Java 由完整的 Java 语言服务器提供支持,能够理解 Java 代码。因此,可以使用代码导航、IntelliSense、重构等功能。当项目变得更大、更复杂时,这些功能尤为重要。接下来进一步了解代码编辑体验。", + "Basic Editing User Guide": "基本编辑用户指南", + "To make the most of VS Code, we strongly recommend reading the {0} user guide. You'll get to know cool tricks about multi-select, formatting, indentation, folding, and much more.": "若要充分利用 VS Code,强烈建议阅读{0}用户指南。您将了解多选、格式化、缩进、折叠等实用技巧。", + "Basic Editing": "基本编辑", + "Code Navigation": "代码导航", + "Code Navigation makes it easy to understand existing codebase. Here to mention a few features that can help you navigate your code repositories.": "代码导航让现有代码库更易于理解。以下功能可以帮助您浏览代码仓库。", + "Go to Definition": "转到定义", + "{0}{1}You can also hover on the symbol to preview its declaration and javadoc. To jump to the definition, hold the {2} key, and click on the symbol.": "{0}{1}还可以将鼠标悬停在符号上,预览其声明和 Javadoc。若要跳转到定义,请按住 {2} 键并点击符号。", + "F12": "F12", + "Go to Implementation": "转到实现", + "{0}{1}For an interface, this shows all the implementors of that interface and for abstract methods, this shows all concrete implementations of that method.": "{0}{1}对于接口,将显示该接口的所有实现;对于抽象方法,将显示该方法的所有具体实现。", + "Go to Type Definition": "转到类型定义", + "This one allows you to go to the definition of the type of the symbol. For example, you have a class member {0}, \"Go to Definition\" will take you to the definition of {1} while \"Go to {2} Definition\" will take you to the definition of {3}.": "此功能可跳转到符号类型的定义。例如,对于类成员 {0},“转到定义”会跳转到 {1} 的定义,而“转到{2}定义”会跳转到 {3} 的定义。", + "Find All References": "查找所有引用", + "{0}{1}This allows you to quickly analyze the impact of your edit or the popularity of your specific method or property throughout your repository.": "{0}{1}此功能可快速分析更改的影响,或特定方法及属性在整个仓库中的使用情况。", + "The commands above will possibly take you to another file. But you can choose to stay using the peeking features below:": "上述命令可能会跳转到其他文件。不过,可以使用以下速览功能留在当前文件中:", + "Peek Definition": "速览定义", + "Peek References": "速览引用", + " Last but not least, you can jump between the matching brackets back and forth: ": " 最后,还可以在匹配的括号之间来回跳转: ", + "Go to Bracket": "转到括号", + "IntelliSense": "IntelliSense", + "IntelliSense is a general term for a variety of code editing features including: code completion, parameter info, quick info, and member lists. IntelliSense features are sometimes called by other names such as \"code completion\", \"content assist\", and \"code hinting.\"": "IntelliSense 是代码补全、参数信息、快速信息和成员列表等多种代码编辑功能的统称。IntelliSense 功能有时也称为“代码补全”“内容辅助”或“代码提示”。", + "IntelliSense works as you type. For example, when you try to invoke some member of an object, a list of all the members is popped up for you to choose from. If you continue typing characters, the list of members (variables, methods, etc.) is filtered to only include members containing your typed characters. Pressing {0} or {1} will insert the selected member.": "IntelliSense 在键入时工作。例如,尝试调用对象的某个成员时,会弹出所有成员的列表供您选择。继续键入字符时,成员列表(变量、方法等)将筛选为仅显示包含已键入字符的成员。按 {0} 或 {1} 可插入所选成员。", + "Tab": "Tab", + "Enter": "Enter", + "Trigger IntelliSense Manually": "手动触发 IntelliSense", + "In most cases, IntelliSense is triggered automatically. You can also press {0} to do it manually. For example, when you're trying to invoke a member function and want to see the parameter info, this will do the magic.": "在大多数情况下,IntelliSense 会自动触发,也可以按 {0} 手动触发。例如,尝试调用成员函数并希望查看参数信息时,可以使用此功能。", + "Refactoring": "重构", + "VS Code Java provides essential refactoring features and makes it productive to modify larger codebase. The most frequently used one is {0}. It's so popular that a dedicated hot key {1} is assigned to it. When you rename a symbol, all its references are also renamed.": "VS Code Java 提供基本的重构功能,让大型代码库的修改更高效。最常用的功能是{0},并为其分配了专用快捷键 {1}。重命名符号时,其所有引用也会随之重命名。", + "Rename": "重命名", + "F2": "F2", + "There are more refactoring features like {0}, {1}, etc. The availability changes corresponding to the current cursor position. All available features are packed in to the {2} context menu. And you can also pop the list by pressing {3}": "还有{0}、{1}等更多重构功能。可用功能会根据当前光标位置变化,所有可用功能均位于{2}上下文菜单中。也可按 {3} 弹出列表", + "Extract": "提取", + "Inline": "内联", + "Refactor": "重构", + "You may also notice the lightbulb near the cursor. It indicates that some {0} are available. In VS Code, Code Actions can provide both refactorings and Quick Fixes for detected issues. To show the full list of available actions, click the lightbulb or press {1}": "您可能还会注意到光标附近的灯泡,它表示有可用的{0}。在 VS Code 中,代码操作可以为检测到的问题提供重构和快速修复。若要显示所有可用操作,请点击灯泡或按 {1}", + "Code Actions": "代码操作", + "More Code Actions": "更多代码操作", + "There are other code actions that are not limited to the cursor position. They are grouped into the {0} context menu. Here's a list of them.": "还有一些代码操作不受光标位置限制,它们位于{0}上下文菜单中,具体如下。", + "Source Action": "源代码操作", + "Organize Imports": "组织导入", + "Override/Implement Methods": "重写/实现方法", + "Generate Getter and Setter": "生成 Getter 和 Setter", + "Generate hashCode() and equals()": "生成 hashCode() 和 equals()", + "Generate toString()": "生成 toString()", + "Generate Constructors": "生成构造函数", + "Generate Delegate Methods": "生成委托方法", + "Project settings are not available from redhat.java.": "无法通过 redhat.java 获取项目设置。", + "Project type information is unavailable.": "项目类型信息不可用。", + "For projects managed by build tools, Java version is specified in build scripts. E.g. to use Java 8, add below lines in {0}:": "对于由构建工具管理的项目,Java 版本在构建脚本中指定。例如,若要使用 Java 8,请在 {0} 中添加以下内容:", + "Open...": "打开...", + "Open Folder...": "打开文件夹...", + "In this 1-minute tutorial, we'll show you how to create a quick-start Java program in VS Code.": "在这个一分钟教程中,我们将演示如何在 VS Code 中快速创建 Java 程序。", + "Setup the Workspace": "设置工作区", + "VS Code Java works directly with {0} that have source code. To setup the workspace, simply open a folder using File >\u00a0{1}": "VS Code Java 可以直接处理包含源代码的{0}。若要设置工作区,只需使用“文件”>\u00a0{1}打开文件夹", + "folders": "文件夹", + "Create a Class": "创建类", + "A program needs an entry and a Java program needs a class to host its entry. To create a class for our quick-start program, {0} and set its name to {1}.{2}Now you can put the code in the new file:": "程序需要一个入口,而 Java 程序需要用类来承载入口。若要为快速入门程序创建类,请{0}并将其命名为 {1}。{2}现在可以将代码放入新文件:", + "Create a File": "创建文件", + "Run the program": "运行程序", + "To run the program, press {0}. By default, the program is launched in the {1}. You should already see the output there.": "按 {0} 运行程序。默认情况下,程序会在{1}中启动,您应该已经可以在那里看到输出。", + "How to Debug?": "如何调试?", + "When you press {0}, you are already debugging. Try setting some breakpoint by clicking on the line numbers before each code line and run the program again. You'll see the execution paused at the breakpoint.{1}While debugging, switch to the {2} to see the variables and call stacks.": "按 {0} 时,调试就已开始。请尝试点击代码行前的行号设置断点,然后再次运行程序,执行会在断点处暂停。{1}调试时,切换到{2}可查看变量和调用堆栈。", + "Congratulations!": "恭喜!", + "Now the quick-start program is running and you are free to build more.{0}What you saw is just a tiny part of VS Code Java. You can do much more with it.": "快速入门程序现已运行,您可以继续构建更多内容。{0}您看到的只是 VS Code Java 的一小部分,它还能帮助您完成更多工作。", + "Documentation": "文档" +} diff --git a/package-lock.json b/package-lock.json index b0032857..ac80068e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@reduxjs/toolkit": "^2.12.0", "@vscode-elements/elements": "^2.5.0", "@vscode/codicons": "^0.0.45", + "@vscode/l10n": "^0.0.18", "@xmldom/xmldom": "^0.8.15", "axios": "^1.20.0", "bootstrap": "^5.3.8", @@ -44,6 +45,7 @@ "@types/vscode": "^1.74.0", "@types/winreg": "^1.2.31", "@types/xmldom": "^0.1.31", + "@vscode/l10n-dev": "^0.0.35", "autoprefixer": "^10.5.4", "bytes": "^3.1.2", "css-loader": "^7.1.5", @@ -70,6 +72,186 @@ "integrity": "sha512-ulkCYfFbYj01ie1MDOyxv2F6SpRN1TOj7fQxbP07D6HmeR+gr2JLSmINKjga2emB+b1L2KGrFKBTc+e00p54nw==", "license": "Apache-2.0" }, + "node_modules/@azure-rest/ai-translation-text": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure-rest/ai-translation-text/-/ai-translation-text-1.0.1.tgz", + "integrity": "sha512-lUs1FfBXjik6EReUEYP1ogkhaSPHZdUV+EB215y7uejuyHgG1RXD2aLsqXQrluZwXcLMdN+bTzxylKBc5xDhgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure-rest/core-client": "^2.3.1", + "@azure/core-auth": "^1.9.0", + "@azure/core-rest-pipeline": "^1.18.0", + "@azure/logger": "^1.1.4", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure-rest/ai-translation-text/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@azure-rest/core-client": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.9.0.tgz", + "integrity": "sha512-6933vNLqh06RR7rumnrq3UZIeBtRLeBHDPMrieDPIljiCaMMwt0nRw++nd3TOxiohtasNtm29rC+b/9ZVKCOqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.24.0", + "@azure/core-tracing": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure-rest/core-client/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@azure/abort-controller": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.2.0.tgz", + "integrity": "sha512-fNAjWnA/nZ2jz31kxR/AqRaUT8ewHBw/WuBIosK0moMy1C9e5ValbDfFdIxJzVOOYaYkV/b2F1S4H/aHiqfVQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/abort-controller/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@azure/core-auth": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.11.0.tgz", + "integrity": "sha512-IUZydyTUkDnYdstOW9pFOOUQlBjAepK5teihDE3x6yxsPJs/hsAaaYpeGxdxrgtOiJbBKSjKW7MDk7AEhb4LRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.25.0.tgz", + "integrity": "sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@azure/core-tracing": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.4.0.tgz", + "integrity": "sha512-eGwxD0AtncrxeBM4tG8R55Pc3rdX1hNW2WibJAgYpCVA6E93mvvVH+LcssoVjOBrSKWS55yEIHsk0X8ctHmfOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-tracing/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@azure/core-util": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.14.0.tgz", + "integrity": "sha512-9n2pWK61veAuN0V20t9lOuoV4CFMdyAZ1ygZzvBGk/pBBJRib/PjL9PLXa/aI2CcPpyHfqVsxxqLCYl6uZlfDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@azure/logger": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.4.0.tgz", + "integrity": "sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/logger/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -105,6 +287,109 @@ "node": ">=14.17.0" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz", + "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -621,6 +906,17 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -807,6 +1103,52 @@ "dev": true, "license": "MIT" }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.9.tgz", + "integrity": "sha512-edSdeAqkdxBVzA1yL1LrLCml1YjyCVvPMtMqJpbF+6K609tHe8V6sQUzFQSGcYNhcuhOceZtjvN32+mpIth30A==", + "dev": true, + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "dev": true, + "license": "0BSD" + }, "node_modules/@vscode-elements/elements": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@vscode-elements/elements/-/elements-2.5.1.tgz", @@ -840,6 +1182,82 @@ "vscode": "^1.75.0" } }, + "node_modules/@vscode/l10n": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", + "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", + "license": "MIT" + }, + "node_modules/@vscode/l10n-dev": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@vscode/l10n-dev/-/l10n-dev-0.0.35.tgz", + "integrity": "sha512-s6uzBXsVDSL69Z85HSqpc5dfKswQkeucY8L00t1TWzGalw7wkLQUKMRwuzqTq+AMwQKrRd7Po14cMoTcd11iDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure-rest/ai-translation-text": "^1.0.0-beta.1", + "debug": "^4.3.4", + "deepmerge-json": "^1.5.0", + "glob": "^10.0.0", + "markdown-it": "^14.0.0", + "node-html-markdown": "^1.3.0", + "pseudo-localization": "^2.4.0", + "web-tree-sitter": "^0.20.8", + "xml2js": "^0.5.0", + "yargs": "^17.7.1" + }, + "bin": { + "vscode-l10n-dev": "dist/cli.js" + } + }, + "node_modules/@vscode/l10n-dev/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vscode/l10n-dev/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/l10n-dev/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -1118,6 +1536,16 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1246,6 +1674,13 @@ "node": "*" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, "node_modules/bootstrap": { "version": "5.3.8", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz", @@ -1424,6 +1859,21 @@ "node": ">=6.0" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -1569,6 +2019,36 @@ } } }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1606,6 +2086,16 @@ } } }, + "node_modules/deepmerge-json": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/deepmerge-json/-/deepmerge-json-1.5.0.tgz", + "integrity": "sha512-jZRrDmBKjmGcqMFEUJ14FjMJwm05Qaked+1vxaALRtF0UAl7lPU8OLWXFxvoeg3jbQM249VPFVn8g2znaQkEtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1636,6 +2126,65 @@ "node": ">=0.3.1" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1650,6 +2199,13 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.420", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.420.tgz", @@ -1657,6 +2213,13 @@ "dev": true, "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", @@ -1681,6 +2244,19 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -1934,6 +2510,23 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", @@ -1994,6 +2587,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -2031,6 +2634,16 @@ "node": ">= 0.4" } }, + "node_modules/get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2134,6 +2747,16 @@ "node": ">=14" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/highlight.js": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.12.0.tgz", @@ -2155,6 +2778,30 @@ "node": ">=0.10.0" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -2298,6 +2945,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2342,6 +2999,22 @@ "node": ">=0.10.0" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jdk-utils": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/jdk-utils/-/jdk-utils-0.7.0.tgz", @@ -2484,6 +3157,26 @@ "dev": true, "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/lit": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.2.tgz", @@ -2549,6 +3242,41 @@ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/markdown-it": { + "version": "14.3.3", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.3.tgz", + "integrity": "sha512-L//tDAkjTjJCU6pBUSBTgs3Kg4InVaZuUZog/b6V12UKhcDQ7S78877ibbCanRExwPuYP1CZD7Gd2dxSy1GXRg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.5.0", + "linkify-it": "^5.0.2", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2558,6 +3286,13 @@ "node": ">= 0.4" } }, + "node_modules/mdurl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", + "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", + "dev": true, + "license": "MIT" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -2727,6 +3462,16 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -2780,6 +3525,30 @@ "license": "MIT", "optional": true }, + "node_modules/node-html-markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-html-markdown/-/node-html-markdown-1.3.0.tgz", + "integrity": "sha512-OeFi3QwC/cPjvVKZ114tzzu+YoR+v9UXW5RwSXGUqGb0qCl0DvP406tzdL7SFn8pZrMyzXoisfG2zcuF9+zw4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-html-parser": "^6.1.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/node-html-parser": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, "node_modules/node-releases": { "version": "2.0.54", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", @@ -2790,6 +3559,19 @@ "node": ">=18" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2839,6 +3621,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -2923,6 +3712,23 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -3120,6 +3926,36 @@ "node": ">=10" } }, + "node_modules/pseudo-localization": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/pseudo-localization/-/pseudo-localization-2.4.0.tgz", + "integrity": "sha512-ISYMOKY8+f+PmiXMFw2y6KLY74LBrv/8ml/VjjoVEV2k+MS+OJZz7ydciK5ntJwxPrKQPTU1+oXq9Mx2b0zEzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat": "^5.0.2", + "get-stdin": "^7.0.0", + "typescript": "^4.7.4", + "yargs": "^17.2.1" + }, + "bin": { + "pseudo-localization": "bin/pseudo-localize" + } + }, + "node_modules/pseudo-localization/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3130,6 +3966,16 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/react": { "version": "19.2.8", "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", @@ -3216,6 +4062,16 @@ "redux": "^5.0.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -3342,6 +4198,16 @@ } } }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -3415,6 +4281,19 @@ "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -3463,6 +4342,64 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/style-loader": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", @@ -3731,6 +4668,13 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -3845,6 +4789,13 @@ "node": ">=10.13.0" } }, + "node_modules/web-tree-sitter": { + "version": "0.20.8", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.20.8.tgz", + "integrity": "sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/webpack": { "version": "5.110.2", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.2.tgz", @@ -4065,12 +5016,112 @@ "dev": true, "license": "MIT" }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, "license": "ISC" + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } } } } diff --git a/package.json b/package.json index f9df847f..ce041a31 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vscode-java-pack", - "displayName": "Extension Pack for Java", - "description": "Popular extensions for Java development that provides Java IntelliSense, debugging, testing, Maven/Gradle support, project management and more", + "displayName": "%extension.displayName%", + "description": "%extension.description%", "license": "MIT", "version": "0.31.2", "publisher": "vscjava", @@ -35,6 +35,7 @@ "url": "https://github.com/Microsoft/vscode-java-pack" }, "main": "./out/extension", + "l10n": "./l10n", "capabilities": { "virtualWorkspaces": false }, @@ -73,11 +74,11 @@ "contributes": { "javaShortcuts": [ { - "title": "$(project) Open Project Settings", + "title": "%shortcuts.projectSettings%", "command": "java.projectSettings" }, { - "title": "$(info) Open Help Center", + "title": "%shortcuts.helpCenter%", "command": "java.welcome" } ], @@ -89,7 +90,7 @@ "steps": [ { "id": "java.runtime", - "title": "Get your runtime ready", + "title": "%walkthrough.java.runtime.title%", "description": "%walkthrough.java.runtime%", "media": { "markdown": "walkthrough/runtime.md" @@ -97,68 +98,68 @@ }, { "id": "java.showProjectExplorer", - "title": "Explore your projects", + "title": "%walkthrough.java.projects.title%", "description": "%walkthrough.java.projects%", "media": { "svg": "walkthrough/projects.svg", - "altText": "Project Explorer" + "altText": "%walkthrough.java.projects.altText%" }, "when": "java:projectManagerActivated && workspaceFolderCount > 0" }, { "id": "java.showProjectExplorer.inactive", - "title": "Explore your project", + "title": "%walkthrough.java.projects.inactive.title%", "description": "%walkthrough.java.projects.inactive%", "media": { "svg": "walkthrough/projects.svg", - "altText": "Project Explorer" + "altText": "%walkthrough.java.projects.altText%" }, "when": "!java:projectManagerActivated || workspaceFolderCount == 0" }, { "id": "java.codeActions", - "title": "View code actions and source actions", + "title": "%walkthrough.java.codeActions.title%", "description": "%walkthrough.java.codeActions%", "media": { "svg": "walkthrough/codeAction.svg", - "altText": "Code actions and source actions" + "altText": "%walkthrough.java.codeActions.altText%" } }, { "id": "java.debugAndTest", - "title": "Launch, debug and test", + "title": "%walkthrough.java.debugAndTest.title%", "description": "%walkthrough.java.debugAndTest%", "media": { "svg": "walkthrough/debugAndTest.svg", - "altText": "Launch, debug and test" + "altText": "%walkthrough.java.debugAndTest.altText%" } }, { "id": "java.extensions", - "title": "Extensions for additional tools and frameworks", + "title": "%walkthrough.java.extensions.title%", "description": "%walkthrough.java.extensions%", "media": { "svg": "walkthrough/extensions.svg", - "altText": "Extensions" + "altText": "%walkthrough.java.extensions.altText%" } }, { "id": "java.more", - "title": "Explore more Java resources", + "title": "%walkthrough.java.more.title%", "description": "%walkthrough.java.more%", "media": { "svg": "walkthrough/helpCenter.svg", - "altText": "Explore more Java resources" + "altText": "%walkthrough.java.more.altText%" }, "when": "!isMac" }, { "id": "java.moreForMac", - "title": "Explore more Java resources", + "title": "%walkthrough.java.more.title%", "description": "%walkthrough.java.more%", "media": { "svg": "walkthrough/helpCenterMac.svg", - "altText": "Explore more Java resources" + "altText": "%walkthrough.java.more.altText%" }, "when": "isMac" } @@ -169,72 +170,72 @@ { "command": "java.installJdk", "category": "Java", - "title": "Install New JDK" + "title": "%commands.installJdk.title%" }, { "command": "java.installJdk.fromWalkthrough", "category": "Java", - "title": "Install New JDK" + "title": "%commands.installJdk.title%" }, { "command": "java.welcome", "category": "Java", - "title": "Help Center" + "title": "%commands.welcome.title%" }, { "command": "java.welcome.fromWalkthrough", "category": "Java", - "title": "Help Center" + "title": "%commands.welcome.title%" }, { "command": "java.classpathConfiguration", "category": "Java", - "title": "Configure Classpath" + "title": "%commands.classpathConfiguration.title%" }, { "command": "java.projectSettings", "category": "Java", - "title": "Open Project Settings" + "title": "%commands.projectSettings.title%" }, { "command": "java.overview", "category": "Java", - "title": "Overview" + "title": "%commands.overview.title%" }, { "command": "java.showReleaseNotes", "category": "Java", - "title": "Show Release Notes" + "title": "%commands.showReleaseNotes.title%" }, { "command": "java.runtime", - "title": "Configure Java Runtime", + "title": "%commands.runtime.title%", "category": "Java" }, { "command": "java.gettingStarted", "category": "Java", - "title": "Tips for Beginners" + "title": "%commands.gettingStarted.title%" }, { "command": "java.extGuide", "category": "Java", - "title": "Extensions Guide" + "title": "%commands.extGuide.title%" }, { "command": "java.formatterSettings", "category": "Java", - "title": "Open Java Formatter Settings with Preview" + "title": "%commands.formatterSettings.title%" }, { "command": "java.formatterSettings.showTextEditor", "category": "Java", - "title": "Open Text Editor", + "title": "%commands.formatterSettings.showTextEditor.title%", "icon": "$(go-to-file)" } ], "configuration": { - "title": "Extension Pack for Java", + "title": "%extension.displayName%", "properties": { "java.help.firstView": { "type": [ @@ -248,26 +249,26 @@ "none" ], "enumDescriptions": [ - "Automatically pick the first experience view", - "Present the Java Overview page", - "Present the Java Beginner Tips page", - "Present the Java Help Center page", - "Do not show any view" + "%configuration.firstView.auto%", + "%configuration.firstView.overview%", + "%configuration.firstView.gettingStarted%", + "%configuration.firstView.welcome%", + "%configuration.firstView.none%" ], "default": "auto", - "description": "Sets the default view which is presented during the first use.", + "description": "%configuration.firstView.description%", "scope": "window" }, "java.help.showReleaseNotes": { "type": "boolean", "default": true, - "description": "Show release notes of Extension Pack for Java on startup.", + "description": "%configuration.showReleaseNotes.description%", "scope": "window" }, "java.help.collectErrorLog": { "type": "boolean", "default": false, - "description": "Whether to send back detailed information from error logs for diagnostic purpose.", + "description": "%configuration.collectErrorLog.description%", "scope": "window" } } @@ -317,7 +318,7 @@ "customEditors": [ { "viewType": "java.formatterSettingsEditor", - "displayName": "Java Formatter Settings Editor", + "displayName": "%customEditors.formatterSettings.displayName%", "selector": [ { "filenamePattern": "*.xml" @@ -339,6 +340,8 @@ "watch": "webpack --config webpack.config.js --watch", "build": "webpack --config webpack.config.js --mode=\"production\"", "test": "node --test", + "l10n:export": "vscode-l10n-dev export -o l10n src", + "l10n:check": "node scripts/check-localization.js --check-extraction", "update-tpn": "node scripts/update-third-party-notice.js" }, "devDependencies": { @@ -354,6 +357,7 @@ "@types/vscode": "^1.74.0", "@types/winreg": "^1.2.31", "@types/xmldom": "^0.1.31", + "@vscode/l10n-dev": "^0.0.35", "autoprefixer": "^10.5.4", "bytes": "^3.1.2", "css-loader": "^7.1.5", @@ -382,6 +386,7 @@ "@reduxjs/toolkit": "^2.12.0", "@vscode-elements/elements": "^2.5.0", "@vscode/codicons": "^0.0.45", + "@vscode/l10n": "^0.0.18", "@xmldom/xmldom": "^0.8.15", "axios": "^1.20.0", "bootstrap": "^5.3.8", diff --git a/package.nls.json b/package.nls.json index 3dba93d4..bbad0728 100644 --- a/package.nls.json +++ b/package.nls.json @@ -13,5 +13,42 @@ "walkthrough.java.extensions": "Install extensions to support additional frameworks such as Spring Boot, Application Servers, key mappings and so on.\n[Browse Recommended Extensions](command:toSide:java.extGuide)", - "walkthrough.java.more": "✨ Help Center provides tips, resources and links to help you get answers to the most common questions to learn Java on VS Code.\n[Open Help Center](command:java.welcome)" + "walkthrough.java.more": "✨ Help Center provides tips, resources and links to help you get answers to the most common questions to learn Java on VS Code.\n[Open Help Center](command:java.welcome)", + + "extension.displayName": "Extension Pack for Java", + "extension.description": "Popular extensions for Java development that provides Java IntelliSense, debugging, testing, Maven/Gradle support, project management and more", + "shortcuts.projectSettings": "$(project) Open Project Settings", + "shortcuts.helpCenter": "$(info) Open Help Center", + "walkthrough.java.runtime.title": "Get your runtime ready", + "walkthrough.java.projects.title": "Explore your projects", + "walkthrough.java.projects.altText": "Project Explorer", + "walkthrough.java.projects.inactive.title": "Explore your project", + "walkthrough.java.codeActions.title": "View code actions and source actions", + "walkthrough.java.codeActions.altText": "Code actions and source actions", + "walkthrough.java.debugAndTest.title": "Launch, debug and test", + "walkthrough.java.debugAndTest.altText": "Launch, debug and test", + "walkthrough.java.extensions.title": "Extensions for additional tools and frameworks", + "walkthrough.java.extensions.altText": "Extensions", + "walkthrough.java.more.title": "Explore more Java resources", + "walkthrough.java.more.altText": "Explore more Java resources", + "commands.installJdk.title": "Install New JDK", + "commands.welcome.title": "Help Center", + "commands.classpathConfiguration.title": "Configure Classpath", + "commands.projectSettings.title": "Open Project Settings", + "commands.overview.title": "Overview", + "commands.showReleaseNotes.title": "Show Release Notes", + "commands.runtime.title": "Configure Java Runtime", + "commands.gettingStarted.title": "Tips for Beginners", + "commands.extGuide.title": "Extensions Guide", + "commands.formatterSettings.title": "Open Java Formatter Settings with Preview", + "commands.formatterSettings.showTextEditor.title": "Open Text Editor", + "configuration.firstView.auto": "Automatically pick the first experience view", + "configuration.firstView.overview": "Present the Java Overview page", + "configuration.firstView.gettingStarted": "Present the Java Beginner Tips page", + "configuration.firstView.welcome": "Present the Java Help Center page", + "configuration.firstView.none": "Do not show any view", + "configuration.firstView.description": "Sets the default view which is presented during the first use.", + "configuration.showReleaseNotes.description": "Show release notes of Extension Pack for Java on startup.", + "configuration.collectErrorLog.description": "Whether to send back detailed information from error logs for diagnostic purpose.", + "customEditors.formatterSettings.displayName": "Java Formatter Settings Editor" } diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json new file mode 100644 index 00000000..b2925de3 --- /dev/null +++ b/package.nls.zh-cn.json @@ -0,0 +1,47 @@ +{ + "walkthrough.title": "开始 Java 开发", + "walkthrough.description": "在轻量、高性能的编辑器中设置强大 Java 工具的第一步!", + "walkthrough.java.runtime": "Extension Pack for Java 需要至少安装一个 Java 运行时。\n[安装 JDK](command:toSide:java.installJdk.fromWalkthrough)", + "walkthrough.java.projects": "Java 项目资源管理器可帮助你管理项目和依赖项,以及创建新的 Java 项目、类和包。\n[查看 Java 项目](command:javaProjectExplorer.focus)", + "walkthrough.java.projects.inactive": "Java 项目资源管理器可帮助你管理项目和依赖项。创建新项目或打开现有文件夹以使用完整功能。\n[打开命令面板](command:workbench.action.quickOpen?%22>java%22)\n__尝试搜索“创建 Java 项目”或“打开文件夹”__", + "walkthrough.java.codeActions": "在编辑器中查找适用于代码的操作:\n - 打开右键菜单,然后选择“重构...”或“源代码操作...”。\n - 单击灯泡💡。", + "walkthrough.java.debugAndTest": "使用调试器运行和调试应用程序。[了解详情...](https://aka.ms/java-walkthrough-debug)\n[测试资源管理器](command:workbench.view.testing.focus)可让你查看、运行和管理项目中的所有测试用例。[了解详情...](https://aka.ms/java-walkthrough-test)\n[显示运行和调试视图](command:workbench.view.debug)", + "walkthrough.java.extensions": "安装扩展以支持 Spring Boot、应用程序服务器、键盘映射等其他框架和工具。\n[浏览推荐的扩展](command:toSide:java.extGuide)", + "walkthrough.java.more": "✨ 帮助中心提供提示、资源和链接,帮助你解答在 VS Code 中学习 Java 时最常见的问题。\n[打开帮助中心](command:java.welcome)", + "extension.displayName": "Extension Pack for Java", + "extension.description": "常用的 Java 开发扩展,提供 Java IntelliSense、调试、测试、Maven/Gradle 支持、项目管理等功能", + "shortcuts.projectSettings": "$(project) 打开项目设置", + "shortcuts.helpCenter": "$(info) 打开帮助中心", + "walkthrough.java.runtime.title": "准备运行时", + "walkthrough.java.projects.title": "探索项目", + "walkthrough.java.projects.altText": "项目资源管理器", + "walkthrough.java.projects.inactive.title": "探索项目", + "walkthrough.java.codeActions.title": "查看代码操作和源代码操作", + "walkthrough.java.codeActions.altText": "代码操作和源代码操作", + "walkthrough.java.debugAndTest.title": "启动、调试和测试", + "walkthrough.java.debugAndTest.altText": "启动、调试和测试", + "walkthrough.java.extensions.title": "适用于其他工具和框架的扩展", + "walkthrough.java.extensions.altText": "扩展", + "walkthrough.java.more.title": "探索更多 Java 资源", + "walkthrough.java.more.altText": "探索更多 Java 资源", + "commands.installJdk.title": "安装新 JDK", + "commands.welcome.title": "帮助中心", + "commands.classpathConfiguration.title": "配置类路径", + "commands.projectSettings.title": "打开项目设置", + "commands.overview.title": "概述", + "commands.showReleaseNotes.title": "显示发行说明", + "commands.runtime.title": "配置 Java 运行时", + "commands.gettingStarted.title": "新手提示", + "commands.extGuide.title": "扩展指南", + "commands.formatterSettings.title": "打开 Java 格式化程序设置及预览", + "commands.formatterSettings.showTextEditor.title": "打开文本编辑器", + "configuration.firstView.auto": "自动选择首次使用时的视图", + "configuration.firstView.overview": "显示 Java 概述页面", + "configuration.firstView.gettingStarted": "显示 Java 新手提示页面", + "configuration.firstView.welcome": "显示 Java 帮助中心页面", + "configuration.firstView.none": "不显示任何视图", + "configuration.firstView.description": "设置首次使用时显示的默认视图。", + "configuration.showReleaseNotes.description": "启动时显示 Extension Pack for Java 的发行说明。", + "configuration.collectErrorLog.description": "是否回传错误日志中的详细信息以用于诊断。", + "customEditors.formatterSettings.displayName": "Java 格式化程序设置编辑器" +} diff --git a/scripts/check-localization.js b/scripts/check-localization.js new file mode 100644 index 00000000..ff172ebf --- /dev/null +++ b/scripts/check-localization.js @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); +const os = require("node:os"); +const { spawnSync } = require("node:child_process"); + +const root = path.join(__dirname, ".."); +const readJson = filename => JSON.parse(fs.readFileSync(filename, "utf8")); + +function invariantTokens(message) { + return [ + ...message.matchAll(/\$\([^)]+\)|\]\(([^)]+)\)|\u{1f4a1}|\u2728|\u{1f504}|\u{1f44d}|\u2666\ufe0f?|\u26a1/gu), + ].map(match => match[1] || match[0]).sort(); +} + +function placeholderTokens(message) { + return [...message.matchAll(/\{(\w+)\}/g)].map(match => match[1]).sort(); +} + +function checkCatalog(source, translated, name) { + assert.deepEqual(Object.keys(translated).sort(), Object.keys(source).sort(), `${name}: catalog keys differ`); + for (const [key, value] of Object.entries(source)) { + const translation = translated[key]; + assert.equal(typeof translation, "string", `${name}: ${key} is not text`); + assert.ok(translation.trim(), `${name}: ${key} is empty`); + assert.deepEqual(invariantTokens(translation), invariantTokens(value), `${name}: ${key} changes a link or icon`); + assert.deepEqual(placeholderTokens(translation), placeholderTokens(value), `${name}: ${key} changes placeholders`); + for (const marker of ["__", "**", "`"]) { + assert.equal(translation.split(marker).length, value.split(marker).length, `${name}: ${key} changes Markdown ${marker}`); + } + } +} + +function checkRuntime(directory = root) { + const source = readJson(path.join(directory, "l10n", "bundle.l10n.json")); + checkCatalog(source, source, "English runtime"); + const locales = fs.readdirSync(path.join(directory, "l10n")).filter(name => /^bundle\.l10n\.[^.]+\.json$/.test(name)); + const manifestLocales = fs.readdirSync(directory).filter(name => /^package\.nls\.[^.]+\.json$/.test(name)) + .map(name => name.slice("package.nls.".length, -".json".length)).sort(); + assert.deepEqual(locales.map(name => name.slice("bundle.l10n.".length, -".json".length)).sort(), + manifestLocales, "Manifest and runtime shipped locales differ"); + for (const name of locales) { + checkCatalog(source, readJson(path.join(directory, "l10n", name)), name); + } +} + +function manifestText(manifest) { + const contributions = manifest.contributes; + return [ + manifest.displayName, manifest.description, contributions.configuration.title, + ...contributions.commands.map(command => command.title), + ...contributions.javaShortcuts.map(shortcut => shortcut.title), + ...contributions.customEditors.map(editor => editor.displayName), + ...contributions.walkthroughs.flatMap(walkthrough => [ + walkthrough.title, walkthrough.description, + ...walkthrough.steps.flatMap(step => [step.title, step.description, ...(step.media.altText ? [step.media.altText] : [])]), + ]), + ...Object.values(contributions.configuration.properties).flatMap(property => [ + property.description, ...property.enumDescriptions || [], + ]), + ]; +} + +function checkManifest(directory = root) { + const source = readJson(path.join(directory, "package.nls.json")); + const manifest = readJson(path.join(directory, "package.json")); + const used = new Set(); + for (const value of manifestText(manifest)) { + assert.match(value, /^%[^%]+%$/, `Manifest UI text is not externalized: ${value}`); + const key = value.slice(1, -1); + assert.ok(Object.hasOwn(source, key), `Missing manifest key: ${key}`); + used.add(key); + } + assert.deepEqual([...used].sort(), Object.keys(source).sort(), "Unused or missing manifest resources"); + checkCatalog(source, source, "English"); + const locales = fs.readdirSync(directory).filter(name => /^package\.nls\.[^.]+\.json$/.test(name)); + assert.ok(locales.length, "No translated manifest catalogs"); + for (const name of locales) { + checkCatalog(source, readJson(path.join(directory, name)), name); + } + return { manifest, source, locales }; +} + +function checkExtraction(directory = root) { + const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "java-pack-l10n-")); + try { + const cli = path.join(path.dirname(require.resolve("@vscode/l10n-dev/package.json")), "dist", "cli.js"); + const result = spawnSync(process.execPath, [cli, "export", "-o", temporary, path.join(directory, "src")], { encoding: "utf8" }); + if (result.error) { + throw result.error; + } + assert.equal(result.status, 0, `Localization extraction failed:\n${result.stdout}\n${result.stderr}`); + const extracted = path.join(temporary, "bundle.l10n.json"); + const actual = fs.existsSync(extracted) ? readJson(extracted) : {}; + assert.deepEqual(readJson(path.join(directory, "l10n", "bundle.l10n.json")), actual, + "Localization extraction drift: run npm run l10n:export and update every translation."); + } finally { + fs.rmSync(temporary, { recursive: true, force: true }); + } +} + +if (require.main === module) { + checkManifest(); + checkRuntime(); + if (process.argv.includes("--check-extraction")) { + checkExtraction(); + } + console.log("Localization catalogs are valid."); +} + +module.exports = { checkCatalog, checkManifest, checkRuntime, checkExtraction, invariantTokens, manifestText, placeholderTokens }; diff --git a/src/beginner-tips/assets/BeginnerTips.tsx b/src/beginner-tips/assets/BeginnerTips.tsx index c2671618..6b1bf7e2 100644 --- a/src/beginner-tips/assets/BeginnerTips.tsx +++ b/src/beginner-tips/assets/BeginnerTips.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "./style.scss"; import "@vscode-elements/elements/dist/vscode-tabs/index.js"; import "@vscode-elements/elements/dist/vscode-tab-header/index.js"; @@ -15,14 +16,14 @@ export default function BeginnerTips({ requiredJdkVersion }: { requiredJdkVersio return (
-

Tips for Beginners

+

{l10n.t("Tips for Beginners")}

- Quick Start - Code Editing - Debugging - FAQ + {l10n.t("Quick Start")} + {l10n.t("Code Editing")} + {l10n.t("Debugging")} + {l10n.t("FAQ")} diff --git a/src/beginner-tips/assets/index.tsx b/src/beginner-tips/assets/index.tsx index f428dbae..8243a397 100644 --- a/src/beginner-tips/assets/index.tsx +++ b/src/beginner-tips/assets/index.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; + import { createRoot } from 'react-dom/client'; import BeginnerTips from "./BeginnerTips"; diff --git a/src/beginner-tips/assets/tabs/CodeEditingPanel.tsx b/src/beginner-tips/assets/tabs/CodeEditingPanel.tsx index 6a3fa8ca..09f04891 100644 --- a/src/beginner-tips/assets/tabs/CodeEditingPanel.tsx +++ b/src/beginner-tips/assets/tabs/CodeEditingPanel.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-table/index.js"; import "@vscode-elements/elements/dist/vscode-table-row/index.js"; import "@vscode-elements/elements/dist/vscode-table-cell/index.js"; @@ -8,117 +10,95 @@ import "@vscode-elements/elements/dist/vscode-table-body/index.js"; const isMac: boolean = navigator.platform.toLowerCase().indexOf("darwin") === 0; export default function CodeEditingPanel() { - const controlKey = !isMac ? Ctrl : ⌘; - const f12Key = !isMac ? Ctrl + F12: ⌘ F12; - const shiftAltF12 = !isMac ? Shift + Alt + F12 : ⌥ ⇧ F12; - const altF12Key = !isMac ? Alt + F12 : ⌥ F12; - const shiftF12 = !isMac ? Shift + F12: ⇧ F12; - const ctrlShiftSlash = !isMac ? Ctrl + Shift + \:⇧ ⌘ \; - const ctrlSpace = !isMac ? Ctrl + Space:⌃ Space; - const ctrlShiftR = !isMac ? Ctrl + Shift + R:⌃ ⇧ R ; - const ctrlDot = !isMac ? Ctrl + .:⌘ .; + const controlKey = !isMac ? {l10n.t("Ctrl")} : ⌘; + const f12Key = !isMac ? {l10n.t("Ctrl + F12")}: {l10n.t("⌘ F12")}; + const shiftAltF12 = !isMac ? {l10n.t("Shift + Alt + F12")} : {l10n.t("⌥ ⇧ F12")}; + const altF12Key = !isMac ? {l10n.t("Alt + F12")} : {l10n.t("⌥ F12")}; + const shiftF12 = !isMac ? {l10n.t("Shift + F12")}: {l10n.t("⇧ F12")}; + const ctrlShiftSlash = !isMac ? {l10n.t("Ctrl + Shift + \\")}:⇧ ⌘ \; + const ctrlSpace = !isMac ? {l10n.t("Ctrl + Space")}:{l10n.t("⌃ Space")}; + const ctrlShiftR = !isMac ? {l10n.t("Ctrl + Shift + R")}:{l10n.t("⌃ ⇧ R")} ; + const ctrlDot = !isMac ? {l10n.t("Ctrl + .")}:⌘ .; return (
-

- VS Code Java is backed by a full Java language server and it understands Java code. Because of that, you get features like Code Navigation, IntelliSense, Refactoring, etc. This is important when your projects get bigger and more complex. Now let's further look at the code editing experience. -

+

{l10n.t("VS Code Java is backed by a full Java language server and it understands Java code. Because of that, you get features like Code Navigation, IntelliSense, Refactoring, etc. This is important when your projects get bigger and more complex. Now let's further look at the code editing experience.")}

-
Basic Editing User Guide
-

- To make the most of VS Code, we strongly recommend reading the Basic Editing user guide. You'll get to know cool tricks about multi-select, formatting, indentation, folding, and much more. -

+
{l10n.t("Basic Editing User Guide")}
+

{richText(l10n.t("To make the most of VS Code, we strongly recommend reading the {0} user guide. You'll get to know cool tricks about multi-select, formatting, indentation, folding, and much more."), [{l10n.t("Basic Editing")}])}

-

Code Navigation

+

{l10n.t("Code Navigation")}

-

- Code Navigation makes it easy to understand existing codebase. Here to mention a few features that can help you navigate your code repositories. -

+

{l10n.t("Code Navigation makes it easy to understand existing codebase. Here to mention a few features that can help you navigate your code repositories.")}

- Go to Definition - F12
You can also hover on the symbol to preview its declaration and javadoc. To jump to the definition, hold the {controlKey} key, and click on the symbol.
+ {l10n.t("Go to Definition")} + {richText(l10n.t("{0}{1}You can also hover on the symbol to preview its declaration and javadoc. To jump to the definition, hold the {2} key, and click on the symbol."), [{l10n.t("F12")},
, controlKey])}
- Go to Implementation - {f12Key}
For an interface, this shows all the implementors of that interface and for abstract methods, this shows all concrete implementations of that method.
+ {l10n.t("Go to Implementation")} + {richText(l10n.t("{0}{1}For an interface, this shows all the implementors of that interface and for abstract methods, this shows all concrete implementations of that method."), [f12Key,
])}
- Go to Type Definition - This one allows you to go to the definition of the type of the symbol. For example, you have a class member someString, "Go to Definition" will take you to the definition of someString while "Go to Type Definition" will take you to the definition of String. + {l10n.t("Go to Type Definition")} + {richText(l10n.t("This one allows you to go to the definition of the type of the symbol. For example, you have a class member {0}, \"Go to Definition\" will take you to the definition of {1} while \"Go to {2} Definition\" will take you to the definition of {3}."), [someString, someString, {l10n.t("Type")}, String])} - Find All References - {shiftAltF12}
This allows you to quickly analyze the impact of your edit or the popularity of your specific method or property throughout your repository.
+ {l10n.t("Find All References")} + {richText(l10n.t("{0}{1}This allows you to quickly analyze the impact of your edit or the popularity of your specific method or property throughout your repository."), [shiftAltF12,
])}
-

- The commands above will possibly take you to another file. But you can choose to stay using the peeking features below: -

+

{l10n.t("The commands above will possibly take you to another file. But you can choose to stay using the peeking features below:")}

- Peek Definition + {l10n.t("Peek Definition")} {altF12Key} - Peek References + {l10n.t("Peek References")} {shiftF12}
-

Last but not least, you can jump between the matching brackets back and forth:

+

{l10n.t(" Last but not least, you can jump between the matching brackets back and forth: ")}

- Go to Bracket + {l10n.t("Go to Bracket")} {ctrlShiftSlash}
-

IntelliSense

-

- IntelliSense is a general term for a variety of code editing features including: code completion, parameter info, quick info, and member lists. IntelliSense features are sometimes called by other names such as "code completion", "content assist", and "code hinting." -

-

- IntelliSense works as you type. For example, when you try to invoke some member of an object, a list of all the members is popped up for you to choose from. If you continue typing characters, the list of members (variables, methods, etc.) is filtered to only include members containing your typed characters. Pressing Tab or Enter will insert the selected member. -

+

{l10n.t("IntelliSense")}

+

{l10n.t("IntelliSense is a general term for a variety of code editing features including: code completion, parameter info, quick info, and member lists. IntelliSense features are sometimes called by other names such as \"code completion\", \"content assist\", and \"code hinting.\"")}

+

{richText(l10n.t("IntelliSense works as you type. For example, when you try to invoke some member of an object, a list of all the members is popped up for you to choose from. If you continue typing characters, the list of members (variables, methods, etc.) is filtered to only include members containing your typed characters. Pressing {0} or {1} will insert the selected member."), [{l10n.t("Tab")}, {l10n.t("Enter")}])}

-
Trigger IntelliSense Manually
-

- In most cases, IntelliSense is triggered automatically. You can also press {ctrlSpace} to do it manually. For example, when you're trying to invoke a member function and want to see the parameter info, this will do the magic. -

+
{l10n.t("Trigger IntelliSense Manually")}
+

{richText(l10n.t("In most cases, IntelliSense is triggered automatically. You can also press {0} to do it manually. For example, when you're trying to invoke a member function and want to see the parameter info, this will do the magic."), [ctrlSpace])}

-

Refactoring

-

- VS Code Java provides essential refactoring features and makes it productive to modify larger codebase. The most frequently used one is Rename. It's so popular that a dedicated hot key F2 is assigned to it. When you rename a symbol, all its references are also renamed. -

-

- There are more refactoring features like Extract, Inline, etc. The availability changes corresponding to the current cursor position. All available features are packed in to the Refactor context menu. And you can also pop the list by pressing {ctrlShiftR} -

-

- You may also notice the lightbulb near the cursor. It indicates that some Code Actions are available. In VS Code, Code Actions can provide both refactorings and Quick Fixes for detected issues. To show the full list of available actions, click the lightbulb or press {ctrlDot} -

+

{l10n.t("Refactoring")}

+

{richText(l10n.t("VS Code Java provides essential refactoring features and makes it productive to modify larger codebase. The most frequently used one is {0}. It's so popular that a dedicated hot key {1} is assigned to it. When you rename a symbol, all its references are also renamed."), [{l10n.t("Rename")}, {l10n.t("F2")}])}

+

{richText(l10n.t("There are more refactoring features like {0}, {1}, etc. The availability changes corresponding to the current cursor position. All available features are packed in to the {2} context menu. And you can also pop the list by pressing {3}"), [{l10n.t("Extract")}, {l10n.t("Inline")}, {l10n.t("Refactor")}, ctrlShiftR])}

+

{richText(l10n.t("You may also notice the lightbulb near the cursor. It indicates that some {0} are available. In VS Code, Code Actions can provide both refactorings and Quick Fixes for detected issues. To show the full list of available actions, click the lightbulb or press {1}"), [{l10n.t("Code Actions")}, ctrlDot])}

-
More Code Actions
-

- There are other code actions that are not limited to the cursor position. They are grouped into the Source Action context menu. Here's a list of them. -

+
{l10n.t("More Code Actions")}
+

{richText(l10n.t("There are other code actions that are not limited to the cursor position. They are grouped into the {0} context menu. Here's a list of them."), [{l10n.t("Source Action")}])}

    -
  • Organize Imports
  • -
  • Override/Implement Methods
  • -
  • Generate Getter and Setter
  • -
  • Generate hashCode() and equals()
  • -
  • Generate toString()
  • -
  • Generate Constructors
  • -
  • Generate Delegate Methods
  • +
  • {l10n.t("Organize Imports")}
  • +
  • {l10n.t("Override/Implement Methods")}
  • +
  • {l10n.t("Generate Getter and Setter")}
  • +
  • {l10n.t("Generate hashCode() and equals()")}
  • +
  • {l10n.t("Generate toString()")}
  • +
  • {l10n.t("Generate Constructors")}
  • +
  • {l10n.t("Generate Delegate Methods")}
diff --git a/src/beginner-tips/assets/tabs/DebuggingPanel.tsx b/src/beginner-tips/assets/tabs/DebuggingPanel.tsx index 0376fa35..76b95c3d 100644 --- a/src/beginner-tips/assets/tabs/DebuggingPanel.tsx +++ b/src/beginner-tips/assets/tabs/DebuggingPanel.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-table/index.js"; import "@vscode-elements/elements/dist/vscode-table-row/index.js"; import "@vscode-elements/elements/dist/vscode-table-cell/index.js"; @@ -8,114 +10,86 @@ import "@vscode-elements/elements/dist/vscode-table-body/index.js"; const isMac: boolean = navigator.platform.toLowerCase().indexOf("darwin") === 0; export default function DebuggingPanel() { - const cF5 = !isMac ? Ctrl + F5 : ⌃ F5; + const cF5 = !isMac ? {l10n.t("Ctrl + F5")} : {l10n.t("⌃ F5")}; const launchConfigPath = !isMac ? .vscode\launch.json : .vscode/launch.json; - const sF11 = !isMac ? Shift + F11 : ⇧ F11; - const csF5 = !isMac ? Ctrl + Shift + F5 : ⇧ ⌘ F5; - const sF5 = !isMac ? Shift + F5 : ⇧ F5; + const sF11 = !isMac ? {l10n.t("Shift + F11")} : {l10n.t("⇧ F11")}; + const csF5 = !isMac ? {l10n.t("Ctrl + Shift + F5")} : {l10n.t("⇧ ⌘ F5")}; + const sF5 = !isMac ? {l10n.t("Shift + F5")} : {l10n.t("⇧ F5")}; return (
-

- One of the key features of Visual Studio Code is its great debugging support. VS Code's built-in debugger helps accelerate your edit, compile and debug loop. -

-

Start Debugging

-

- There are multiple ways to start debugging a Java program. By pressing F5, the current program will be launched. You can also start by clicking the "Debug" codelens on top of the main function. This is super handy when you have multiple main entries. You can also launch a program without debugging by pressing {cF5}. -

-

- By default, VS Code Java launches the program using Integrated Terminal. As you enter the debug mode, you should also see the Debug View. This view shows all the runtime info of your program. -

+

{l10n.t("One of the key features of Visual Studio Code is its great debugging support. VS Code's built-in debugger helps accelerate your edit, compile and debug loop.")}

+

{l10n.t("Start Debugging")}

+

{richText(l10n.t("There are multiple ways to start debugging a Java program. By pressing {0}, the current program will be launched. You can also start by clicking the {1} codelens on top of the {2} function. This is super handy when you have multiple main entries. You can also launch a program {3} debugging by pressing {4}."), [{l10n.t("F5")}, {l10n.t("\"Debug\"")}, main, {l10n.t("without")}, {cF5}])}

+

{richText(l10n.t("By default, VS Code Java launches the program using {0}. As you enter the debug mode, you should also see the {1}. This view shows all the runtime info of your program."), [{l10n.t("Integrated Terminal")}, {l10n.t("Debug View")}])}

-
Debug Configurations
-

- VS Code Java automatically generates debug configurations. In VS Code, those configurations are called Launch Configurations and they are persisted in {launchConfigPath}. To work with more sophisticated debug scenarios, please explore the Launch Options that are supported by VS Code. -

+
{l10n.t("Debug Configurations")}
+

{richText(l10n.t("VS Code Java automatically generates debug configurations. In VS Code, those configurations are called {0} and they are persisted in {1}. To work with more sophisticated debug scenarios, please explore the {2} that are supported by VS Code."), [{l10n.t("Launch Configurations")}, launchConfigPath, {l10n.t("Launch Options")}])}

-

Breakpoints

-

- Breakpoints can be toggled by clicking on the editor margin or using F9 on the current line. Finer breakpoint control (enable/disable/reapply) can be done in the Debug View's BREAKPOINTS section. -

-

- You can also set Conditional Breakpoints based on expressions, hit counts, or a combination of both. -

+

{l10n.t("Breakpoints")}

+

{richText(l10n.t("Breakpoints can be toggled by clicking on the editor margin or using {0} on the current line. Finer breakpoint control (enable/disable/reapply) can be done in the Debug View's BREAKPOINTS section."), [{l10n.t("F9")}])}

+

{richText(l10n.t("You can also set {0} based on expressions, hit counts, or a combination of both."), [{l10n.t("Conditional Breakpoints")}])}

- Expression condition - The breakpoint will be hit whenever the expression evaluates to true + {l10n.t("Expression condition")} + {richText(l10n.t("The breakpoint will be hit whenever the expression evaluates to {0}"), [true])} - Hit count - The 'hit count' controls how many times a breakpoint needs to be hit before it will 'break' execution + {l10n.t("Hit count")} + {l10n.t("The 'hit count' controls how many times a breakpoint needs to be hit before it will 'break' execution")} -

- You can add a condition and/or hit count when creating the breakpoint (with the Add Conditional Breakpoint action) or when modifying an existing one (with the Edit Breakpoint action). In both cases, an inline text box with a drop-down menu opens where you can enter expressions. -

+

{richText(l10n.t("You can add a condition and/or hit count when creating the breakpoint (with the {0} action) or when modifying an existing one (with the Edit Breakpoint action). In both cases, an inline text box with a drop-down menu opens where you can enter expressions."), [{l10n.t("Add Conditional Breakpoint")}])}

-
Logpoints
-

- A Logpoint is a variant of a breakpoint that does not "break" into the debugger but instead logs a message to the console. Logpoints are especially useful for injecting logging while debugging production servers that cannot be paused or stopped. -

-

- A Logpoint is represented by a ♦️ shaped icon. Log messages are plain text but can include expressions to be evaluated within curly braces ('{"{ }"}'). -

+
{l10n.t("Logpoints")}
+

{l10n.t("A Logpoint is a variant of a breakpoint that does not \"break\" into the debugger but instead logs a message to the console. Logpoints are especially useful for injecting logging while debugging production servers that cannot be paused or stopped.")}

+

{l10n.t("A Logpoint is represented by a ♦️ shaped icon. Log messages are plain text but can include expressions to be evaluated within curly braces ('{ }').")}

-

Debug Actions

-

- Once a debug session starts, the Debug toolbar will appear on the top of the editor. You can control the execution flow using the actions below. -

+

{l10n.t("Debug Actions")}

+

{l10n.t("Once a debug session starts, the Debug toolbar will appear on the top of the editor. You can control the execution flow using the actions below.")}

- Continue/Pause - F5 + {l10n.t("Continue/Pause")} + {l10n.t("F5")} - Step Over - F10 + {l10n.t("Step Over")} + {l10n.t("F10")} - Step Into - F11 + {l10n.t("Step Into")} + {l10n.t("F11")} - Step Out + {l10n.t("Step Out")} {sF11} - Restart + {l10n.t("Restart")} {csF5} - Stop + {l10n.t("Stop")} {sF5} -

Inspect Variables

-

- Variables can be inspected in the VARIABLES section of the Debug view or by hovering over their source in the editor. Variable values and expression evaluation are relative to the selected stack frame in the CALL STACK section. -

-

- Variable values can be modified with the Set Value action from the variable's context menu. Or you can double-click the value and enter a new one. Variables and expressions can also be evaluated and watched in the Debug view's WATCH section. -

-

Hot Code Replace ⚡

-

- Yes, you can apply code changes without restarting the running program. Click on the ⚡ icon in the debug toolbar to apply code changes. When you see failures, don't worry. It is safe to continue running the program, but you may notice discrepancies between the source code and the program. -

+

{l10n.t("Inspect Variables")}

+

{richText(l10n.t("Variables can be inspected in the {0} section of the Debug view or by hovering over their source in the editor. Variable values and expression evaluation are relative to the selected stack frame in the {1} section."), [{l10n.t("VARIABLES")}, {l10n.t("CALL STACK")}])}

+

{richText(l10n.t("Variable values can be modified with the {0} action from the variable's context menu. Or you can {1} the value and enter a new one. Variables and expressions can also be evaluated and watched in the Debug view's {2} section."), [{l10n.t("Set Value")}, {l10n.t("double-click")}, {l10n.t("WATCH")}])}

+

{l10n.t("Hot Code Replace ⚡")}

+

{richText(l10n.t("Yes, you can apply code changes without restarting the running program. Click on the {0} icon in the {1} to apply code changes. When you see failures, don't worry. It is safe to continue running the program, but you may notice discrepancies between the source code and the program."), [⚡, {l10n.t("debug toolbar")}])}

-
Limitations
-

- Hot Code Replace (HCR) sounds magical but it does have limitations. In short, you can only change the code inside an existing function. Here are some scenarios that HCR will NOT work: -

+
{l10n.t("Limitations")}
+

{richText(l10n.t("Hot Code Replace (HCR) sounds magical but it does have limitations. In short, you can only change the code inside an existing function. Here are some scenarios that HCR will {0} work:"), [{l10n.t("NOT")}])}

    -
  • Adding a new member function
  • -
  • Changing the signature of an existing function
  • -
  • Changing the value of static members (but you can do so using the VARIABLES panel when the program is paused)
  • -
  • Referencing new classes/packages
  • +
  • {l10n.t("Adding a new member function")}
  • +
  • {l10n.t("Changing the signature of an existing function")}
  • +
  • {l10n.t("Changing the value of static members (but you can do so using the VARIABLES panel when the program is paused)")}
  • +
  • {l10n.t("Referencing new classes/packages")}
diff --git a/src/beginner-tips/assets/tabs/FaqPanel.tsx b/src/beginner-tips/assets/tabs/FaqPanel.tsx index 0fca5cee..a7b9eb21 100644 --- a/src/beginner-tips/assets/tabs/FaqPanel.tsx +++ b/src/beginner-tips/assets/tabs/FaqPanel.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-table/index.js"; import "@vscode-elements/elements/dist/vscode-table-row/index.js"; import "@vscode-elements/elements/dist/vscode-table-cell/index.js"; @@ -27,74 +29,50 @@ export default function FaqPanel({ requiredJdkVersion }: { requiredJdkVersion: n return (
-
Feedback Channels
-

- VS Code Java is new, and we are here to help. -

+
{l10n.t("Feedback Channels")}
+

{l10n.t("VS Code Java is new, and we are here to help.")}

- Ask Questions - vscode-java Gitter channel is recommended to ask for help + {l10n.t("Ask Questions")} + {richText(l10n.t("{0} Gitter channel is recommended to ask for help"), [{l10n.t("vscode-java")}])} - Open Issues - vscode-java-pack GitHub repo is recommended for opening bugs + {l10n.t("Open Issues")} + {richText(l10n.t("{0} GitHub repo is recommended for opening bugs"), [{l10n.t("vscode-java-pack")}])} - Other Feedback - @VSCodeJava is the handle to mention on twitter + {l10n.t("Other Feedback")} + {richText(l10n.t("{0} is the handle to mention on twitter"), [{l10n.t("@VSCodeJava")}])}
-

Why do I see the JDK errors?

-

- JDK {requiredJdkVersion}+ is required to run the installed Java language support (redhat.java) extension. A compatible bundled runtime can satisfy this requirement; otherwise, a compatible local JDK is needed. To set the language-server launch JDK explicitly, configure java.jdt.ls.java.home. Runtime selection and startup diagnostics are provided by redhat.java; open the Java logs for details. -

-

- The Configure Java Runtime page configures project JDKs, not the language-server launch JDK. Your projects can use older JDKs independently of the tooling requirement. -

+

{l10n.t("Why do I see the JDK errors?")}

+

{richText(l10n.t("{0} to run the installed Java language support (redhat.java) extension. A compatible bundled runtime can satisfy this requirement; otherwise, a compatible local JDK is needed. To set the language-server launch JDK explicitly, configure {1}. Runtime selection and startup diagnostics are provided by redhat.java; {2} for details."), [{richText(l10n.t("{0} is required"), [JDK {requiredJdkVersion}+])}, java.jdt.ls.java.home, {l10n.t("open the Java logs")}])}

+

{richText(l10n.t("The {0} page configures project JDKs, not the language-server launch JDK. Your projects can use older JDKs independently of the tooling requirement."), [{l10n.t("Configure Java Runtime")}])}

-

Can I run my Java 8 project with JDK 1.8?

-

- Yes. The JDK {requiredJdkVersion} requirement is just for running the Java language support (redhat.java) extension itself. You can still configure a different runtime JDK for your project via the user setting "java.configuration.runtimes". The extension will pick a matching JDK to compile/run your project according to the compiler version specified by the project build file. -

+

{l10n.t("Can I run my Java 8 project with JDK 1.8?")}

+

{richText(l10n.t("Yes. The JDK {0} requirement is just for running the Java language support (redhat.java) extension itself. You can still configure a different runtime {1} via the user setting {2}. The extension will pick a matching JDK to compile/run your project according to the compiler version specified by the project build file."), [requiredJdkVersion, {l10n.t("JDK for your project")}, "java.configuration.runtimes"])}

{runtimeSampleCode}
-

Why do I see tons of problems and red squiggles?

-

- The problems are from VS Code Java when it tries to compile and build your codebase. If you experience this on your first use, it's possibly because of missing dependencies. To fix it, you probably want to start from fixing the project configuration files, e.g. pom.xml and build.gradle. After you make changes to those files, try Update Project Configuration and Force Compilation. -

-

- It can also happen after you work with one project for a while. Try Clean Workspace to get rid of any intermediate output from the language server. -

-

- If the problem persists, follow the Troubleshooting Guide. For advanced users, the Client Logs and Server Logs will definitely help you understand what is going on. -

+

{l10n.t("Why do I see tons of problems and red squiggles?")}

+

{richText(l10n.t("The problems are from VS Code Java when it tries to compile and build your codebase. If you experience this on your first use, it's possibly because of {0}. To fix it, you probably want to start from fixing the project configuration files, e.g. {1} and {2}. After you make changes to those files, try {3} and {4}."), [{l10n.t("missing dependencies")}, pom.xml, build.gradle, {l10n.t("Update Project Configuration")}, {l10n.t("Force Compilation")}])}

+

{richText(l10n.t("It can also happen after you work with one project for a while. Try {0} to get rid of any intermediate output from the language server."), [{l10n.t("Clean Workspace")}])}

+

{richText(l10n.t("If the problem persists, follow the {0}. For advanced users, the {1} and {2} will definitely help you understand what is going on."), [{l10n.t("Troubleshooting Guide")}, {l10n.t("Client Logs")}, {l10n.t("Server Logs")}])}

-

Why can't I see any IntelliSense suggestions?

-

- VS Code Java needs to compile your code before it can provide suggestions. When it's working, you should see a spinning 🔄 on the right end of the status bar. And it will show 👍 when it's done. And you should be able to use all the features. -

-

- It could take longer for the language server to load a project which references lots of dependencies. Those dependencies need to be resolved and downloaded from the internet. So the network connection plays a critical role in the process. -

-

Can I use Lombok?

-

- Yes. You'll need to install the Lombok extension, which enables VS Code to process Lombok annotations. To learn more about alternatives and details, visit this page. -

-

Can I develop Android apps using VS Code Java?

-

- Sorry, it's not supported now. -

-

How to troubleshoot the problems?

-

- You could click F1 {"->"} Java: Open all log files to get the logs. Also learn more at Troubleshooting Guide. -

+

{l10n.t("Why can't I see any IntelliSense suggestions?")}

+

{l10n.t("VS Code Java needs to compile your code before it can provide suggestions. When it's working, you should see a spinning 🔄 on the right end of the status bar. And it will show 👍 when it's done. And you should be able to use all the features.")}

+

{l10n.t("It could take longer for the language server to load a project which references lots of dependencies. Those dependencies need to be resolved and downloaded from the internet. So the network connection plays a critical role in the process.")}

+

{l10n.t("Can I use Lombok?")}

+

{richText(l10n.t("Yes. You'll need to install the {0} extension, which enables VS Code to process Lombok annotations. To learn more about alternatives and details, visit {1}."), [{l10n.t("Lombok")}, {l10n.t("this page")}])}

+

{l10n.t("Can I develop Android apps using VS Code Java?")}

+

{l10n.t("Sorry, it's not supported now.")}

+

{l10n.t("How to troubleshoot the problems?")}

+

{richText(l10n.t("You could click {0} -> {1} to get the logs. Also learn more at {2}."), [{l10n.t("F1")}, {l10n.t("Java: Open all log files")}, {l10n.t("Troubleshooting Guide")}])}

); diff --git a/src/beginner-tips/assets/tabs/QuickStartPanel.tsx b/src/beginner-tips/assets/tabs/QuickStartPanel.tsx index 7653b95d..c33c4169 100644 --- a/src/beginner-tips/assets/tabs/QuickStartPanel.tsx +++ b/src/beginner-tips/assets/tabs/QuickStartPanel.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; +import { richText } from "../../../l10n/richText"; const isMac: boolean = navigator.platform.toLowerCase().indexOf("darwin") === 0; @@ -15,44 +17,28 @@ export default function QuickStartPanel() { ); const openFolderLink = isMac ? - Open... + {l10n.t("Open...")} : - Open Folder... + {l10n.t("Open Folder...")} ; return (
-

- In this 1-minute tutorial, we'll show you how to create a quick-start Java program in VS Code. -

-

Setup the Workspace

-

- VS Code Java works directly with folders that have source code. To setup the workspace, simply open a folder using File {">"}  - {openFolderLink} -

-

Create a Class

-

- A program needs an entry and a Java program needs a class to host its entry. To create a class for our quick-start program, Create a File and set its name to QuickStart.java.
- Now you can put the code in the new file: -

+

{l10n.t("In this 1-minute tutorial, we'll show you how to create a quick-start Java program in VS Code.")}

+

{l10n.t("Setup the Workspace")}

+

{richText(l10n.t("VS Code Java works directly with {0} that have source code. To setup the workspace, simply open a folder using File > {1}"), [{l10n.t("folders")}, openFolderLink])}

+

{l10n.t("Create a Class")}

+

{richText(l10n.t("A program needs an entry and a Java program needs a class to host its entry. To create a class for our quick-start program, {0} and set its name to {1}.{2}Now you can put the code in the new file:"), [{l10n.t("Create a File")}, QuickStart.java,
])}

{codeSample}
-

Run the program

-

- To run the program, press F5. By default, the program is launched in the Integrated Terminal. You should already see the output there. -

+

{l10n.t("Run the program")}

+

{richText(l10n.t("To run the program, press {0}. By default, the program is launched in the {1}. You should already see the output there."), [{l10n.t("F5")}, {l10n.t("Integrated Terminal")}])}

-
How to Debug?
-

- When you press F5, you are already debugging. Try setting some breakpoint by clicking on the line numbers before each code line and run the program again. You'll see the execution paused at the breakpoint.
- While debugging, switch to the Debug View to see the variables and call stacks. -

+
{l10n.t("How to Debug?")}
+

{richText(l10n.t("When you press {0}, you are already debugging. Try setting some breakpoint by clicking on the line numbers before each code line and run the program again. You'll see the execution paused at the breakpoint.{1}While debugging, switch to the {2} to see the variables and call stacks."), [{l10n.t("F5")},
, {l10n.t("Debug View")}])}

-

Congratulations!

-

- Now the quick-start program is running and you are free to build more.
- What you saw is just a tiny part of VS Code Java. You can do much more with it. -

+

{l10n.t("Congratulations!")}

+

{richText(l10n.t("Now the quick-start program is running and you are free to build more.{0}What you saw is just a tiny part of VS Code Java. You can do much more with it."), [
])}

); } \ No newline at end of file diff --git a/src/beginner-tips/index.ts b/src/beginner-tips/index.ts index f9d9e42e..0a5fc3fb 100644 --- a/src/beginner-tips/index.ts +++ b/src/beginner-tips/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap } from "../l10n/host"; import * as path from "path"; import * as vscode from "vscode"; import { sendInfo } from "vscode-extension-telemetry-wrapper"; @@ -8,7 +9,6 @@ import { getNonce, webviewCmdLinkHandler } from "../utils"; import { getRequiredJdkVersion } from "../java-runtime/utils/upstreamApi"; const WEBVIEW_ID = "java.gettingStarted"; -const WEBVIEW_TITLE = "Tips for Beginners"; export async function javaGettingStartedCmdHandler(context: vscode.ExtensionContext, _operationId: string) { BeginnerTipsPage.createOrShow(context.extensionPath); @@ -45,7 +45,7 @@ class BeginnerTipsPage { if ((columnOrwebviewPanel as vscode.WebviewPanel).viewType) { this._panel = columnOrwebviewPanel as vscode.WebviewPanel; } else { - this._panel = vscode.window.createWebviewPanel(BeginnerTipsPage.viewType, WEBVIEW_TITLE, columnOrwebviewPanel as vscode.ViewColumn, { + this._panel = vscode.window.createWebviewPanel(BeginnerTipsPage.viewType, vscode.l10n.t("Tips for Beginners"), columnOrwebviewPanel as vscode.ViewColumn, { enableScripts: true, localResourceRoots: [ vscode.Uri.file(path.join(this._extensionPath, 'out')) @@ -55,6 +55,7 @@ class BeginnerTipsPage { }); } + this._panel.title = vscode.l10n.t("Tips for Beginners"); this._panel.iconPath = { light: vscode.Uri.file(path.join(this._extensionPath, "caption.light.svg")), dark: vscode.Uri.file(path.join(this._extensionPath, "caption.dark.svg")) @@ -113,16 +114,17 @@ class BeginnerTipsPage { const cspSource = this._panel!.webview.cspSource; return ` - + - ${WEBVIEW_TITLE} + ${escapeHtml(vscode.l10n.t("Tips for Beginners"))} - + ${localizationBootstrap(nonce)} +
diff --git a/src/commands/handler.ts b/src/commands/handler.ts index 84825d6e..af3b04d1 100644 --- a/src/commands/handler.ts +++ b/src/commands/handler.ts @@ -10,7 +10,7 @@ import { gt, eq } from "semver"; import { fetchInitProps } from "../welcome/index"; export async function createMavenProjectCmdHandler(_context: vscode.ExtensionContext) { - if (!await validateAndRecommendExtension("vscjava.vscode-maven", "Maven extension is recommended to help create Java projects and work with custom goals.", true)) { + if (!await validateAndRecommendExtension("vscjava.vscode-maven", vscode.l10n.t("Maven extension is recommended to help create Java projects and work with custom goals."), true)) { return; } @@ -20,7 +20,7 @@ export async function createMavenProjectCmdHandler(_context: vscode.ExtensionCon // TODO: add entry to create standalone Java file export async function createSpringBootProjectCmdHandler(_context: vscode.ExtensionContext) { - if (!await validateAndRecommendExtension("vscjava.vscode-spring-initializr", "Spring Initializr extension is recommended to help create Spring Boot projects and manage dependencies.", true)) { + if (!await validateAndRecommendExtension("vscjava.vscode-spring-initializr", vscode.l10n.t("Spring Initializr extension is recommended to help create Spring Boot projects and manage dependencies."), true)) { return; } @@ -28,7 +28,7 @@ export async function createSpringBootProjectCmdHandler(_context: vscode.Extensi } export async function createQuarkusProjectCmdHandler(_context: vscode.ExtensionContext) { - if (!await validateAndRecommendExtension("redhat.vscode-quarkus", "Quarkus Tools for Visual Studio Code is recommended to help create Quarkus projects and for an all-in-one Quarkus application development experience.", true)) { + if (!await validateAndRecommendExtension("redhat.vscode-quarkus", vscode.l10n.t("Quarkus Tools for Visual Studio Code is recommended to help create Quarkus projects and for an all-in-one Quarkus application development experience."), true)) { return; } @@ -36,7 +36,7 @@ export async function createQuarkusProjectCmdHandler(_context: vscode.ExtensionC } export async function createMicroProfileStarterProjectCmdHandler(_context: vscode.ExtensionContext) { - if (!await validateAndRecommendExtension("microProfile-community.mp-starter-vscode-ext", "MicroProfile Starter for Visual Studio Code is recommended to generate starter projects for Eclipse MicroProfile.", true)) { + if (!await validateAndRecommendExtension("microProfile-community.mp-starter-vscode-ext", vscode.l10n.t("MicroProfile Starter for Visual Studio Code is recommended to generate starter projects for Eclipse MicroProfile."), true)) { return; } @@ -51,10 +51,10 @@ export async function showExtensionCmdHandler(_context: vscode.ExtensionContext, export async function installExtensionCmdHandler(_context: vscode.ExtensionContext, operationId: string, extensionName: string, displayName: string) { sendInfo(operationId, { extName: extensionName }); - return vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: `Installing ${displayName||extensionName}...`}, _progress => { + return vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: vscode.l10n.t("Installing {0}...", displayName || extensionName)}, _progress => { return vscode.commands.executeCommand("workbench.extensions.installExtension", extensionName); }).then(() => { - vscode.window.showInformationMessage(`Successfully installed ${displayName||extensionName}.`); + vscode.window.showInformationMessage(vscode.l10n.t("Successfully installed {0}.", displayName || extensionName)); }); } @@ -120,10 +120,10 @@ export async function toggleAwtDevelopmentHandler(context: vscode.ExtensionConte try { await workspaceConfig.update("filteredTypes", filteredTypes, vscode.ConfigurationTarget.Workspace); } catch (e) { - vscode.window.showErrorMessage((e as Error).message); + vscode.window.showErrorMessage(vscode.l10n.t("Unable to update Java AWT development settings: {0}", (e as Error).message)); return; } fetchInitProps(context); - vscode.window.showInformationMessage(`Java AWT development is ${enable ? "enabled" : "disabled"}.`); + vscode.window.showInformationMessage(enable ? vscode.l10n.t("Java AWT development is enabled.") : vscode.l10n.t("Java AWT development is disabled.")); } diff --git a/src/daemon/index.ts b/src/daemon/index.ts index 36cd902e..250f1ac7 100644 --- a/src/daemon/index.ts +++ b/src/daemon/index.ts @@ -320,9 +320,10 @@ async function checkIfJavaServerCrashed(wait: number = 0/*ms*/) { sendInfo("", { name: "corrupted-cache", }); - const ans = await vscode.window.showErrorMessage("Java extension cannot start due to corrupted workspace cache, please try to clean the workspace.", - "Clean and Restart"); - if (ans === "Clean and Restart") { + const clean = { title: vscode.l10n.t("Clean and Restart") }; + const ans = await vscode.window.showErrorMessage(vscode.l10n.t("Java extension cannot start due to corrupted workspace cache, please try to clean the workspace."), + clean); + if (ans === clean) { sendInfo("", { name: "clean-cache-action", }); diff --git a/src/ext-guide/assets/index.ts b/src/ext-guide/assets/index.ts index 9bdc00f3..bd6ea164 100644 --- a/src/ext-guide/assets/index.ts +++ b/src/ext-guide/assets/index.ts @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; +import * as l10n from "@vscode/l10n"; + import "../../assets/vscode.scss"; import "bootstrap/js/src/tab"; const $ = require("jquery"); @@ -59,7 +62,7 @@ function updateSelection() { return; } - $btnSelected.text(`Install Selected (${$checked.length})`); + $btnSelected.text(l10n.t("Install Selected ({0})", $checked.length)); bsShow($btnSelected); } diff --git a/src/ext-guide/index.ts b/src/ext-guide/index.ts index 7c3aa7fc..3e917652 100644 --- a/src/ext-guide/index.ts +++ b/src/ext-guide/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap } from "../l10n/host"; import * as vscode from "vscode"; import * as path from "path"; import { getExtensionContext, getNonce } from "../utils"; @@ -14,7 +15,7 @@ export async function javaExtGuideCmdHandler(context: vscode.ExtensionContext, o return; } - javaExtGuideView = vscode.window.createWebviewPanel("java.extGuide", "Java Extensions Guide", { + javaExtGuideView = vscode.window.createWebviewPanel("java.extGuide", vscode.l10n.t("Java Extensions Guide"), { viewColumn: vscode.ViewColumn.One, }, { enableScripts: true, @@ -30,6 +31,7 @@ function onDidDisposeWebviewPanel() { } async function initializeJavaExtGuideView(context: vscode.ExtensionContext, webviewPanel: vscode.WebviewPanel, onDisposeCallback: () => void, operationId: string) { + webviewPanel.title = vscode.l10n.t("Java Extensions Guide"); webviewPanel.iconPath = { light: vscode.Uri.file(path.join(context.extensionPath, "caption.light.svg")), dark: vscode.Uri.file(path.join(context.extensionPath, "caption.dark.svg")) @@ -76,21 +78,22 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string const nonce = getNonce(); const cspSource = webviewPanel.webview.cspSource; return ` - + - Java Extensions Guide + ${escapeHtml(vscode.l10n.t("Java Extensions Guide"))} + ${localizationBootstrap(nonce)}
-

Java Extensions Guide

-
Recommended extensions for Java development.
+

${escapeHtml(vscode.l10n.t("Java Extensions Guide"))}

+
${escapeHtml(vscode.l10n.t("Recommended extensions for Java development."))}
@@ -101,16 +104,16 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string @@ -125,9 +128,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -136,9 +137,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -146,9 +145,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -156,9 +153,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -166,9 +161,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -176,9 +169,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -194,9 +185,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -204,9 +193,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -214,9 +201,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -232,9 +217,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -250,9 +233,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -260,9 +241,7 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
- +
@@ -273,52 +252,28 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
-

- Java Linting, Intellisense, formatting, refactoring, Maven/Gradle support and more. -

-

- Debug Java applications. -

-

- Manage Java projects, dependencies, and generate packages. -

-

- Run and debug JUnit & TestNG test cases. -

-

- Manage Maven projects, work with goals & dependencies, generate projects from archetypes. -

-

- Detect and fix quality issues as you write code. -

-

- Spring Boot-specific support for \".java\" files. As well as validation and content assist for Spring Boot \"application.properties\", \"application.yml\" properties files. -

-

- A collection of extensions to develop Java microservices with Eclipse MicroProfile -

-

- Quarkus Tools for Visual Studio Code. -

-

- Manage and publish to servers and runtimes like Tomcat, Apache Felix, and Karaf. -

-

- Port of Eclipse keyboard shortcuts. -

-

- Port of IntelliJ IDEA Keybindings, including for WebStorm, PyCharm, PHP Storm, etc. -

+

${escapeHtml(vscode.l10n.t("Java Linting, Intellisense, formatting, refactoring, Maven/Gradle support and more."))}

+

${escapeHtml(vscode.l10n.t("Debug Java applications."))}

+

${escapeHtml(vscode.l10n.t("Manage Java projects, dependencies, and generate packages."))}

+

${escapeHtml(vscode.l10n.t("Run and debug JUnit & TestNG test cases."))}

+

${escapeHtml(vscode.l10n.t("Manage Maven projects, work with goals & dependencies, generate projects from archetypes."))}

+

${escapeHtml(vscode.l10n.t("Detect and fix quality issues as you write code."))}

+

${escapeHtml(vscode.l10n.t("Spring Boot-specific support for \".java\" files. As well as validation and content assist for Spring Boot \"application.properties\", \"application.yml\" properties files."))}

+

${escapeHtml(vscode.l10n.t("A collection of extensions to develop Java microservices with Eclipse MicroProfile"))}

+

${escapeHtml(vscode.l10n.t("Quarkus Tools for Visual Studio Code."))}

+

${escapeHtml(vscode.l10n.t("Manage and publish to servers and runtimes like Tomcat, Apache Felix, and Karaf."))}

+

${escapeHtml(vscode.l10n.t("Port of Eclipse keyboard shortcuts."))}

+

${escapeHtml(vscode.l10n.t("Port of IntelliJ IDEA Keybindings, including for WebStorm, PyCharm, PHP Storm, etc."))}

- Learn More + ${escapeHtml(vscode.l10n.t("Learn More"))}

- - + +
diff --git a/src/formatter-settings/assets/features/formatterSettings/FormatterSettingView.tsx b/src/formatter-settings/assets/features/formatterSettings/FormatterSettingView.tsx index 328d44a7..f954a268 100644 --- a/src/formatter-settings/assets/features/formatterSettings/FormatterSettingView.tsx +++ b/src/formatter-settings/assets/features/formatterSettings/FormatterSettingView.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; +import { formatterExampleLabel } from "../../labels"; import { useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; import { Dispatch } from "@reduxjs/toolkit"; @@ -11,20 +13,19 @@ import Setting from "./components/Setting"; import { renderWhitespace } from "../../whitespace"; import { onWillChangeExampleKind, onWillDownloadAndUse, onWillInitialize } from "../../utils"; -const categories = [ - { key: Category.Indentation, label: "Indentation", example: ExampleKind.INDENTATION_EXAMPLE }, - { key: Category.BlankLine, label: "Blank Lines", example: ExampleKind.BLANKLINE_EXAMPLE }, - { key: Category.Comment, label: "Comment", example: ExampleKind.COMMENT_EXAMPLE }, - { key: Category.InsertLine, label: "Insert Line", example: ExampleKind.INSERTLINE_EXAMPLE }, - { key: Category.Whitespace, label: "Whitespace", example: ExampleKind.WHITESPACE_EXAMPLE }, - { key: Category.Wrapping, label: "Wrapping", example: ExampleKind.WRAPPING_EXAMPLE }, -]; - const FormatterSettingsView = (): JSX.Element => { + const categories = [ + { key: Category.Indentation, label: formatterExampleLabel(ExampleKind.INDENTATION_EXAMPLE), example: ExampleKind.INDENTATION_EXAMPLE }, + { key: Category.BlankLine, label: l10n.t("Blank Lines"), example: ExampleKind.BLANKLINE_EXAMPLE }, + { key: Category.Comment, label: formatterExampleLabel(ExampleKind.COMMENT_EXAMPLE), example: ExampleKind.COMMENT_EXAMPLE }, + { key: Category.InsertLine, label: formatterExampleLabel(ExampleKind.INSERTLINE_EXAMPLE), example: ExampleKind.INSERTLINE_EXAMPLE }, + { key: Category.Whitespace, label: formatterExampleLabel(ExampleKind.WHITESPACE_EXAMPLE), example: ExampleKind.WHITESPACE_EXAMPLE }, + { key: Category.Wrapping, label: formatterExampleLabel(ExampleKind.WRAPPING_EXAMPLE), example: ExampleKind.WRAPPING_EXAMPLE }, + ]; const activeCategory: Category = useSelector((state: any) => state.formatterSettings.activeCategory); const contentText: string = useSelector((state: any) => state.formatterSettings.formattedContent); const readOnly: boolean = useSelector((state: any) => state.formatterSettings.readOnly); - const title: string = "Java Formatter Settings" + (readOnly ? " (Read Only)" : ""); + const title = readOnly ? l10n.t("Java Formatter Settings (Read Only)") : l10n.t("Java Formatter Settings"); const dispatch: Dispatch = useDispatch(); const onClickNaviBar = (cat: Category, exampleKind: ExampleKind) => { @@ -73,7 +74,7 @@ const FormatterSettingsView = (): JSX.Element => {
{naviBar}
diff --git a/src/formatter-settings/assets/features/formatterSettings/components/Setting.tsx b/src/formatter-settings/assets/features/formatterSettings/components/Setting.tsx index e3410f8c..4f72726d 100644 --- a/src/formatter-settings/assets/features/formatterSettings/components/Setting.tsx +++ b/src/formatter-settings/assets/features/formatterSettings/components/Setting.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; +import { formatterCandidateLabel, formatterSettingLabel } from "../../../labels"; import "@vscode-elements/elements/dist/vscode-single-select/index.js"; import "@vscode-elements/elements/dist/vscode-option/index.js"; @@ -48,11 +50,11 @@ const Setting = (): JSX.Element => {
- {willBeOverriden ? "When enabled, the indentation settings will be overriden based on the file contents." : ""} + {willBeOverriden ? l10n.t("When enabled, the indentation settings will be overriden based on the file contents.") : ""}
@@ -63,16 +65,17 @@ const Setting = (): JSX.Element => { } return (
handleClick(setting.exampleKind)}> - {setting.name}. + {formatterSettingLabel(setting)}. handleSelect(setting, e.target.value)} > {setting.candidates.map(candidate => ( - {candidate} + {formatterCandidateLabel(candidate)} ))} @@ -81,7 +84,7 @@ const Setting = (): JSX.Element => { case ValueKind.Number: return (
handleClick(setting.exampleKind)}> - +
); diff --git a/src/formatter-settings/assets/index.tsx b/src/formatter-settings/assets/index.tsx index b95c1a03..e787721b 100644 --- a/src/formatter-settings/assets/index.tsx +++ b/src/formatter-settings/assets/index.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; + import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { Provider } from "react-redux"; diff --git a/src/formatter-settings/assets/labels.ts b/src/formatter-settings/assets/labels.ts new file mode 100644 index 00000000..99c5b2c8 --- /dev/null +++ b/src/formatter-settings/assets/labels.ts @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import * as l10n from "@vscode/l10n"; +import { SupportedSettings, VSCodeSettings } from "../FormatterConstants"; +import { ExampleKind, JavaFormatterSetting } from "../types"; + +export function formatterSettingLabel(setting: JavaFormatterSetting): string { + switch (setting.id) { + case SupportedSettings.TABULATION_CHAR: return l10n.t("Indentation policy"); + case SupportedSettings.TABULATION_SIZE: return l10n.t("Tab size"); + case VSCodeSettings.DETECT_INDENTATION: return l10n.t("Detect indentation from file content"); + case SupportedSettings.INSERT_NEW_LINE_IN_CONTROL_STATEMENTS: return l10n.t("In control statements"); + case SupportedSettings.INSERT_NEW_LINE_BEFORE_WHILE_IN_DO_STATEMENT: return l10n.t("Before 'while' in a 'do' statement"); + case SupportedSettings.INSERT_NEW_LINE_BEFORE_FINALLY_IN_TRY_STATEMENT: return l10n.t("Before 'finally' in a 'try' statement"); + case SupportedSettings.INSERT_NEW_LINE_BEFORE_ELSE_IN_IF_STATEMENT: return l10n.t("Before 'else' in an 'if' statement"); + case SupportedSettings.INSERT_NEW_LINE_BEFORE_CATCH_IN_TRY_STATEMENT: return l10n.t("Before 'catch' in a 'try' statement"); + case SupportedSettings.INSERT_NEW_LINE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER: return l10n.t("Before closing brace in array initializer"); + case SupportedSettings.INSERT_NEW_LINE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER: return l10n.t("After opening brace in array initializer"); + case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION: return l10n.t("After annotation"); + case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PARAMETER: return l10n.t("After annotation on parameters"); + case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PACKAGE: return l10n.t("After annotation on packages"); + case SupportedSettings.INSERT_NEW_LINE_AFTER_ANNOTATION_ON_ENUM_CONSTANT: return l10n.t("After annotation on enum constants"); + case SupportedSettings.PUT_EMPTY_STATEMENT_ON_NEW_LINE: return l10n.t("Before empty statement"); + case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_TYPE_DECLARATION: return l10n.t("In empty class declaration"); + case SupportedSettings.KEEP_TYPE_DECLARATION_ON_ONE_LINE: return l10n.t("Reserve line for class declaration"); + case SupportedSettings.KEEP_RECORD_DECLARATION_ON_ONE_LINE: return l10n.t("Reserve line for record declaration"); + case SupportedSettings.KEEP_RECORD_CONSTRUCTOR_ON_ONE_LINE: return l10n.t("Reserve line for record constructor"); + case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_METHOD_BODY: return l10n.t("In empty method body"); + case SupportedSettings.KEEP_METHOD_BODY_ON_ONE_LINE: return l10n.t("Reserve line for method body"); + case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ENUM_DECLARATION: return l10n.t("In empty enum declaration"); + case SupportedSettings.KEEP_ENUM_DECLARATION_ON_ONE_LINE: return l10n.t("Reserve line for enum declaration"); + case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ENUM_CONSTANT: return l10n.t("In empty enum constant"); + case SupportedSettings.KEEP_ENUM_CONSTANT_DECLARATION_ON_ONE_LINE: return l10n.t("Reserve line for enum constant declaration"); + case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ANONYMOUS_TYPE_DECLARATION: return l10n.t("In empty anonymous type declaration"); + case SupportedSettings.KEEP_ANONYMOUS_TYPE_DECLARATION_ON_ONE_LINE: return l10n.t("Reserve line for anonymous type declaration"); + case SupportedSettings.INSERT_NEW_LINE_IN_EMPTY_ANNOTATION_DECLARATION: return l10n.t("In empty annotation declaration"); + case SupportedSettings.KEEP_ANNOTATION_DECLARATION_ON_ONE_LINE: return l10n.t("Reserve line for annotation declaration"); + case SupportedSettings.BLANK_LINES_BETWEEN_TYPE_DECLARATIONS: return l10n.t("Between class declarations"); + case SupportedSettings.BLANK_LINES_BETWEEN_IMPORT_GROUPS: return l10n.t("Between import groups"); + case SupportedSettings.BLANK_LINES_BEFORE_PACKAGE: return l10n.t("Before package declarations"); + case SupportedSettings.BLANK_LINES_BEFORE_IMPORTS: return l10n.t("Before import declarations"); + case SupportedSettings.BLANK_LINES_BEFORE_MEMBER_TYPE: return l10n.t("Between member type declarations"); + case SupportedSettings.NUMBER_OF_EMPTY_LINES_TO_PRESERVE: return l10n.t("Empty lines to preserve"); + case SupportedSettings.LINESPLIT: return l10n.t("Maximum line width"); + case SupportedSettings.COMMENT_LINELENGTH: return l10n.t("Maximum comment line length"); + case SupportedSettings.COMMENT_LINE_LENGTH: return l10n.t("Maximum comment line length"); + case SupportedSettings.COMMENT_INDENTPARAMETERDESCRIPTION: return l10n.t("Indent wrapped parameter description"); + case SupportedSettings.COMMENT_INDENT_PARAMETER_DESCRIPTION: return l10n.t("Indent wrapped parameter description"); + case SupportedSettings.COMMENT_FORMATHEADER: return l10n.t("Enable header comment formatting"); + case SupportedSettings.COMMENT_FORMAT_HEADER: return l10n.t("Enable header comment formatting"); + case SupportedSettings.COMMENT_FORMATTER_COMMENT: return l10n.t("Enable comment formatting"); + case SupportedSettings.COMMENT_FORMATTER_COMMENT_CORE: return l10n.t("Enable comment formatting"); + case SupportedSettings.COMMENT_FORMAT_BLOCK_COMMENTS: return l10n.t("Enable block comment formatting"); + case SupportedSettings.FORMAT_LINE_COMMENTS: return l10n.t("Enable line comment formatting"); + case SupportedSettings.COMMENT_COUNT_LINE_LENGTH_FROM_STARTING_POSITION: return l10n.t("Count line length from starting position"); + case SupportedSettings.COMMENT_CLEARBLANKLINES: return l10n.t("Remove blank lines in comment"); + case SupportedSettings.COMMENT_CLEAR_BLANK_LINES: return l10n.t("Remove blank lines in comment"); + case SupportedSettings.COMMENT_CLEAR_BLANK_LINES_IN_JAVADOC_COMMENT: return l10n.t("Remove blank lines in Javadoc"); + case SupportedSettings.COMMENT_CLEAR_BLANK_LINES_IN_BLOCK_COMMENT: return l10n.t("Remove blank lines in block comment"); + case SupportedSettings.COMMENT_ON_OFF_TAGS: return l10n.t("Use On/Off tags"); + case SupportedSettings.INSERT_SPACE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER: return l10n.t("Before closing brace in array initializer"); + case SupportedSettings.INSERT_SPACE_BEFORE_FIRST_INITIALIZER: return l10n.t("Before first initializer"); + case SupportedSettings.INSERT_SPACE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER: return l10n.t("After opening brace in array initializer"); + case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_PAREN_IN_CAST: return l10n.t("After closing parenthesis in cast"); + case SupportedSettings.INSERT_SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENTS: return l10n.t("After closing angle bracket in type"); + default: return setting.name; + } +} + +export function formatterCandidateLabel(candidate: string): string { + switch (candidate) { + case "tab": return l10n.t("tab"); + case "space": return l10n.t("space"); + case "never": return l10n.t("never"); + case "if empty": return l10n.t("if empty"); + case "if at most one item": return l10n.t("if at most one item"); + default: return candidate; + } +} + +export function formatterExampleLabel(kind: ExampleKind): string { + switch (kind) { + case ExampleKind.INDENTATION_EXAMPLE: return l10n.t("Indentation"); + case ExampleKind.BLANKLINE_EXAMPLE: return l10n.t("Blank line"); + case ExampleKind.COMMENT_EXAMPLE: return l10n.t("Comment"); + case ExampleKind.INSERTLINE_EXAMPLE: return l10n.t("Insert Line"); + case ExampleKind.BRACED_CODE_TYPE_EXAMPLE: return l10n.t("Braced type"); + case ExampleKind.BRACED_CODE_RECORD_EXAMPLE: return l10n.t("Braced record"); + case ExampleKind.BRACED_CODE_ENUM_EXAMPLE: return l10n.t("Braced enum"); + case ExampleKind.ANNOTATION_AND_ANONYMOUS_EXAMPLE: return l10n.t("Annotation and anonymous"); + case ExampleKind.WHITESPACE_EXAMPLE: return l10n.t("Whitespace"); + case ExampleKind.WRAPPING_EXAMPLE: return l10n.t("Wrapping"); + } +} diff --git a/src/formatter-settings/index.ts b/src/formatter-settings/index.ts index 06298b76..3ea1312b 100644 --- a/src/formatter-settings/index.ts +++ b/src/formatter-settings/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap } from "../l10n/host"; import { compareVersions } from "compare-versions"; import * as fse from "fs-extra"; import * as path from "path"; @@ -133,9 +134,10 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi case "onWillDownloadAndUse": { const settingsUrl = vscode.workspace.getConfiguration("java").get(JavaConstants.SETTINGS_URL_KEY); if (!settingsUrl || !isRemote(settingsUrl)) { - vscode.window.showErrorMessage("The active formatter profile does not exist or is not remote, please check it in the Settings and try again.", - "Open Settings").then((result) => { - if (result === "Open Settings") { + const openSettings = { title: vscode.l10n.t("Open Settings") }; + vscode.window.showErrorMessage(vscode.l10n.t("The active formatter profile does not exist or is not remote, please check it in the Settings and try again."), + openSettings).then((result) => { + if (result === openSettings) { openFormatterSettings(); } }); @@ -160,17 +162,18 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi const nonce = getNonce(); const cspSource = this.webviewPanel!.webview.cspSource; return ` - + - Java Formatter Settings + ${escapeHtml(vscode.l10n.t("Java Formatter Settings"))} + ${localizationBootstrap(nonce)} - +
`; @@ -182,7 +185,7 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi } const javaExt = vscode.extensions.getExtension("redhat.java"); if (!javaExt) { - vscode.window.showErrorMessage("The extension 'redhat.java' is not installed. Please install it and run this command again."); + vscode.window.showErrorMessage(vscode.l10n.t("The extension 'redhat.java' is not installed. Please install it and run this command again.")); const err: Error = new Error("The extension 'redhat.java' is not installed."); setUserError(err); sendError(err); @@ -190,7 +193,7 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi } const javaExtVersion: string = javaExt.packageJSON.version; if (compareVersions(javaExtVersion, JavaConstants.MINIMUM_JAVA_EXTENSION_VERSION) < 0) { - vscode.window.showErrorMessage(`The extension version of 'redhat.java' is too stale. Please install at least ${JavaConstants.MINIMUM_JAVA_EXTENSION_VERSION} and run this command again.`); + vscode.window.showErrorMessage(vscode.l10n.t("The extension version of 'redhat.java' is too stale. Please install at least {0} and run this command again.", JavaConstants.MINIMUM_JAVA_EXTENSION_VERSION)); const err: Error = new Error(`The extension version of 'redhat.java' (${javaExtVersion}) is too stale.`); setUserError(err); sendError(err); @@ -216,8 +219,9 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi private async parseProfileAndUpdate(document: vscode.TextDocument): Promise { const content: ProfileContent = parseProfile(document); if (!content.isValid) { - vscode.window.showErrorMessage("The current profile is invalid, please check it in the Settings and try again.", "Open Settings").then((anwser) => { - if (anwser === "Open Settings") { + const openSettings = { title: vscode.l10n.t("Open Settings") }; + vscode.window.showErrorMessage(vscode.l10n.t("The current profile is invalid, please check it in the Settings and try again."), openSettings).then((answer) => { + if (answer === openSettings) { openFormatterSettings(); } }); @@ -243,9 +247,11 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi private onChangeProfileSettings(): void { if (this.webviewPanel?.visible) { - vscode.window.showInformationMessage(`Formatter Profile settings have been changed, do you want to reload this editor?`, - "Yes", "No").then(async (result) => { - if (result === "Yes") { + const yes = { title: vscode.l10n.t("Yes") }; + const no = { title: vscode.l10n.t("No") }; + vscode.window.showInformationMessage(vscode.l10n.t("Formatter Profile settings have been changed, do you want to reload this editor?"), + yes, no).then(async (result) => { + if (result === yes) { vscode.commands.executeCommand("workbench.action.webview.reloadWebviewAction"); } }); @@ -331,17 +337,21 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi this.readOnly = false; if (!this.settingsUrl) { sendInfo(operationId, { formatterProfileKind: "undefined" }); - await vscode.window.showInformationMessage("No active Formatter Profile found, do you want to create a default one?", - "Yes", "No").then((result) => { - if (result === "Yes") { + const yes = { title: vscode.l10n.t("Yes") }; + const no = { title: vscode.l10n.t("No") }; + await vscode.window.showInformationMessage(vscode.l10n.t("No active Formatter Profile found, do you want to create a default one?"), + yes, no).then((result) => { + if (result === yes) { addDefaultProfile(this.context); } }); } else if (isRemote(this.settingsUrl)) { sendInfo(operationId, { formatterProfileKind: "remote" }); - this.checkedProfileSettings = await vscode.window.showInformationMessage("The active formatter profile is remote, do you want to open it in read-only mode or download and use it locally?", - "Open in read-only mode", "Download and use it locally").then(async (result) => { - if (result === "Open in read-only mode") { + const readOnly = { title: vscode.l10n.t("Open in read-only mode") }; + const download = { title: vscode.l10n.t("Download and use it locally") }; + this.checkedProfileSettings = await vscode.window.showInformationMessage(vscode.l10n.t("The active formatter profile is remote, do you want to open it in read-only mode or download and use it locally?"), + readOnly, download).then(async (result) => { + if (result === readOnly) { const content = await downloadFile(this.settingsUrl!); if (!content) { return false; @@ -349,7 +359,7 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi remoteProfileProvider.setContent(this.settingsUrl!, content); this.readOnly = true; return true; - } else if (result === "Download and use it locally") { + } else if (result === download) { this.downloadAndUse(this.settingsUrl!); return false; } else { @@ -362,11 +372,13 @@ export class JavaFormatterSettingsEditorProvider implements vscode.CustomTextEdi } if (!(await fse.pathExists(this.profilePath))) { sendInfo(operationId, { formatterProfileKind: "notExist" }); - await vscode.window.showInformationMessage("The active formatter profile does not exist, please check it in the Settings and try again.", - "Open Settings", "Generate a default profile").then((result) => { - if (result === "Open Settings") { + const openSettings = { title: vscode.l10n.t("Open Settings") }; + const generate = { title: vscode.l10n.t("Generate a default profile") }; + await vscode.window.showInformationMessage(vscode.l10n.t("The active formatter profile does not exist, please check it in the Settings and try again."), + openSettings, generate).then((result) => { + if (result === openSettings) { openFormatterSettings(); - } else if (result === "Generate a default profile") { + } else if (result === generate) { addDefaultProfile(this.context); } }); diff --git a/src/formatter-settings/utils.ts b/src/formatter-settings/utils.ts index a9d665d0..01cf822e 100644 --- a/src/formatter-settings/utils.ts +++ b/src/formatter-settings/utils.ts @@ -103,13 +103,13 @@ export function parseProfile(document: vscode.TextDocument): ProfileContent { const settingContent: string = new XMLSerializer().serializeToString(setting); const id = setting.getAttribute("id"); if (!id) { - diagnostics.push(new vscode.Diagnostic(new vscode.Range(new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1), new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1 + settingContent.length)), "The setting has no valid 'id' property.", vscode.DiagnosticSeverity.Error)); + diagnostics.push(new vscode.Diagnostic(new vscode.Range(new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1), new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1 + settingContent.length)), vscode.l10n.t("The setting has no valid 'id' property."), vscode.DiagnosticSeverity.Error)); continue; } const value = settings[j].getAttribute("value"); if (!value) { // value maybe "" or null, "" is an valid value comes from deleting the values in the inpux box of the editor, and we will still push diagnostic here. - diagnostics.push(new vscode.Diagnostic(new vscode.Range(new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1), new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1 + settingContent.length)), "The setting has no valid 'value' property.", vscode.DiagnosticSeverity.Error)); + diagnostics.push(new vscode.Diagnostic(new vscode.Range(new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1), new vscode.Position(setting.lineNumber - 1, setting.columnNumber - 1 + settingContent.length)), vscode.l10n.t("The setting has no valid 'value' property."), vscode.DiagnosticSeverity.Error)); if (value === null) { continue; } @@ -140,7 +140,7 @@ export function parseProfile(document: vscode.TextDocument): ProfileContent { continue; } const elementRange = new vscode.Range(new vscode.Position(valueNode.lineNumber - 1, valueNode.columnNumber), new vscode.Position(valueNode.lineNumber - 1, valueNode.columnNumber + valueNode.nodeValue.length)); - diagnostics.push(new vscode.Diagnostic(elementRange, `"${value}" is not supported in id: "${setting.id}".`, vscode.DiagnosticSeverity.Error)); + diagnostics.push(new vscode.Diagnostic(elementRange, vscode.l10n.t('"{0}" is not supported in id: "{1}".', value, setting.id), vscode.DiagnosticSeverity.Error)); profileSettings.delete(setting.id); setting.value = FormatterConverter.profile2WebViewConvert(setting.id, getDefaultValue(setting.id))!; continue; @@ -162,10 +162,12 @@ export async function downloadFile(settingsUrl: string): Promise { try { return (await axios.get(settingsUrl)).data; } catch (e) { - const answer = await vscode.window.showErrorMessage(`Failed to get the profile content from uri: ${settingsUrl}. Do you want to retry?`, "Retry", "Open Settings"); - if (answer === "Retry") { + const retry = { title: vscode.l10n.t("Retry") }; + const settings = { title: vscode.l10n.t("Open Settings") }; + const answer = await vscode.window.showErrorMessage(vscode.l10n.t("Failed to get the profile content from uri: {0}. Do you want to retry?", settingsUrl), retry, settings); + if (answer === retry) { return downloadFile(settingsUrl); - } else if (answer === "Open Settings") { + } else if (answer === settings) { openFormatterSettings(); } return ""; diff --git a/src/install-jdk/assets/features/InstallJDKView.tsx b/src/install-jdk/assets/features/InstallJDKView.tsx index 36f52728..1f38a613 100644 --- a/src/install-jdk/assets/features/InstallJDKView.tsx +++ b/src/install-jdk/assets/features/InstallJDKView.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import "@vscode-elements/elements/dist/vscode-tabs/index.js"; import "@vscode-elements/elements/dist/vscode-tab-header/index.js"; @@ -18,12 +19,12 @@ export default function InstallJDKView() { return (
-

Install New JDK

+

{l10n.t("Install New JDK")}

{/*reserved for introduction*/}

- Adoptium's Temurin - Others + {l10n.t("Adoptium's Temurin")} + {l10n.t("Others")} @@ -32,10 +33,10 @@ export default function InstallJDKView() {
-

After you finish JDK installation, please reload Visual Studio Code to make it effective.

+

{l10n.t("After you finish JDK installation, please reload Visual Studio Code to make it effective.")}

- Reload Window - Having trouble? + {l10n.t("Reload Window")} + {l10n.t("Having trouble?")}
diff --git a/src/install-jdk/assets/features/components/AdoptiumJDKPanel.tsx b/src/install-jdk/assets/features/components/AdoptiumJDKPanel.tsx index c27b65ca..fc0f5d4c 100644 --- a/src/install-jdk/assets/features/components/AdoptiumJDKPanel.tsx +++ b/src/install-jdk/assets/features/components/AdoptiumJDKPanel.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import "@vscode-elements/elements/dist/vscode-progress-ring/index.js"; import "@vscode-elements/elements/dist/vscode-radio-group/index.js"; @@ -66,15 +67,13 @@ const AdoptiumJDKPanel = () => { defaultChecked={obj.version === releases.most_recent_lts} checked={obj.version === currentVersion} onClick={() => handleVersionChange(obj.version)} - >{obj.version}{obj.isLts && " (LTS)"}); + >{obj.version}{obj.isLts && l10n.t(" (LTS)")}); const downloadPanel = asset ?
downloadJDK(asset)}>
-
- Download -
+
{l10n.t("Download")}
@@ -100,12 +99,12 @@ const AdoptiumJDKPanel = () => { return (
- + {versionElements} - - hotspot + + {l10n.t("hotspot")} {downloadPanel}
diff --git a/src/install-jdk/assets/features/components/OtherJDKsPanel.tsx b/src/install-jdk/assets/features/components/OtherJDKsPanel.tsx index 9ca1b06f..12c3b8cc 100644 --- a/src/install-jdk/assets/features/components/OtherJDKsPanel.tsx +++ b/src/install-jdk/assets/features/components/OtherJDKsPanel.tsx @@ -19,9 +19,7 @@ export default function OtherJDKsPanel() { return (
); diff --git a/src/install-jdk/assets/index.tsx b/src/install-jdk/assets/index.tsx index 059a5050..f4daeb05 100644 --- a/src/install-jdk/assets/index.tsx +++ b/src/install-jdk/assets/index.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; + import { createRoot } from 'react-dom/client'; import App from './App'; import { Provider } from 'react-redux'; diff --git a/src/install-jdk/index.ts b/src/install-jdk/index.ts index ab4a2468..b9d48629 100644 --- a/src/install-jdk/index.ts +++ b/src/install-jdk/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap } from "../l10n/host"; import * as path from 'path'; import * as vscode from 'vscode'; import { getNonce, openExternalLinkFromWebview, webviewCmdLinkHandler } from '../utils'; @@ -63,7 +64,7 @@ class InstallJdkPage { if ((columnOrwebviewPanel as vscode.WebviewPanel).viewType) { this._panel = columnOrwebviewPanel as vscode.WebviewPanel; } else { - this._panel = vscode.window.createWebviewPanel(InstallJdkPage.viewType, "Install New JDK", columnOrwebviewPanel as vscode.ViewColumn, { + this._panel = vscode.window.createWebviewPanel(InstallJdkPage.viewType, vscode.l10n.t("Install New JDK"), columnOrwebviewPanel as vscode.ViewColumn, { enableScripts: true, localResourceRoots: [ vscode.Uri.file(path.join(this._extensionPath, 'out')) @@ -73,6 +74,7 @@ class InstallJdkPage { }); } + this._panel.title = vscode.l10n.t("Install New JDK"); this._panel.iconPath = { light: vscode.Uri.file(path.join(extensionPath, "caption.light.svg")), dark: vscode.Uri.file(path.join(extensionPath, "caption.dark.svg")) @@ -146,16 +148,17 @@ class InstallJdkPage { const cspSource = this._panel!.webview.cspSource; return ` - + - React App + ${escapeHtml(vscode.l10n.t("Install New JDK"))} - + ${localizationBootstrap(nonce)} +
diff --git a/src/java-runtime/assets/ProjectJDKPanel.tsx b/src/java-runtime/assets/ProjectJDKPanel.tsx index 6949780a..70ee43c4 100644 --- a/src/java-runtime/assets/ProjectJDKPanel.tsx +++ b/src/java-runtime/assets/ProjectJDKPanel.tsx @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../l10n/richText"; +import { projectTypeLabel } from "../../l10n/display"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import "@vscode-elements/elements/dist/vscode-table/index.js"; import "@vscode-elements/elements/dist/vscode-table-body/index.js"; @@ -34,11 +37,11 @@ export function ProjectJDKPanel({ jdkEntries, projectRuntimes, javaDotHome, tool const projectTypeHint = (projectType: ProjectType) => { switch (projectType) { case "Maven": - return setShowHintFor("Maven")} icon-only title="For projects managed by build tools, Java version is specified in build scripts(e.g. pom.xml).">; + return setShowHintFor("Maven")} icon-only title={l10n.t("For projects managed by build tools, Java version is specified in build scripts(e.g. pom.xml).")}>; case "Gradle": - return setShowHintFor("Gradle")} icon-only title="For projects managed by build tools, Java version is specified in build scripts(e.g. build.gradle).">; + return setShowHintFor("Gradle")} icon-only title={l10n.t("For projects managed by build tools, Java version is specified in build scripts(e.g. build.gradle).")}>; default: - return setShowHintFor("Others")} icon-only title="For folders containing .java files, but not managed by build tools like Maven/Gradle, a default JDK is used.">; + return setShowHintFor("Others")} icon-only title={l10n.t("For folders containing .java files, but not managed by build tools like Maven/Gradle, a default JDK is used.")}>; } }; @@ -59,17 +62,12 @@ export function ProjectJDKPanel({ jdkEntries, projectRuntimes, javaDotHome, tool .map((p, index) => ( {p.name} -
{p.projectType}{projectTypeHint(p.projectType)}
+
{projectTypeLabel(p.projectType)}{projectTypeHint(p.projectType)}
- { - hasBuildTool(p) ? -
+ {hasBuildTool(p) ?
{p.sourceLevel} - onClickEdit(p)} title="Edit"> -
- : - - } + onClickEdit(p)} title={l10n.t("Edit")}> +
: }
)); @@ -79,40 +77,31 @@ export function ProjectJDKPanel({ jdkEntries, projectRuntimes, javaDotHome, tool return (
-

Configure Runtime for Projects

+

{l10n.t("Configure Runtime for Projects")}

{javaDotHome ? ( -

Language server runtime reported by redhat.java: {javaDotHome} (Java {toolingJreVersion}).

+

{richText(l10n.t("Language server runtime reported by redhat.java: {0} (Java {1})."), [{javaDotHome}, toolingJreVersion])}

) : ( -

Language server runtime information is not available yet. Use Refresh after redhat.java starts, or open the Java logs for details.

+

{richText(l10n.t("Language server runtime information is not available yet. Use Refresh after redhat.java starts, or {0} for details."), [{l10n.t("open the Java logs")}])}

)} -

JDK {requiredJdkVersion}+ is required for the language server only; your projects can use older JDKs. Open language-server runtime settings.

- {javaHomeError &&

{javaHomeError} Open Java Logs.

} - {javaHomeWarning &&

{javaHomeWarning} Open Java Logs.

} - {projectJdkError &&

{projectJdkError} Open Java Logs.

} +

{richText(l10n.t("JDK {0}+ is required for the language server only; your projects can use older JDKs. {1}."), [requiredJdkVersion, {l10n.t("Open language-server runtime settings")}])}

+ {javaHomeError &&

{javaHomeError} {l10n.t("Open Java Logs")}.

} + {javaHomeWarning &&

{javaHomeWarning} {l10n.t("Open Java Logs")}.

} + {projectJdkError &&

{projectJdkError} {l10n.t("Open Java Logs")}.

} {!javaDotHome && } - {projectEntries.length > 0 &&

Manage Java runtime for your projects. If you don't have a valid Java runtime, you can download one.

} - { - projectEntries.length > 0 ? - + {projectEntries.length > 0 &&

{richText(l10n.t("Manage Java runtime for your projects. If you don't have a valid Java runtime, you can {0} one."), [{l10n.t("download")}])}

} + {projectEntries.length > 0 ? - Project Name - Type - Java Version + {l10n.t("Project Name")} + {l10n.t("Type")} + {l10n.t("Java Version")} {projectEntries} - - : -
- {projectJdkError ? -

Project information could not be fully loaded. Please refresh to try again.

- : -

No project detected yet. Please refresh later if Java extension is importing your projects.

- } -
- } - Refresh +
:
+ {projectJdkError ?

{l10n.t("Project information could not be fully loaded. Please refresh to try again.")}

:

{l10n.t("No project detected yet. Please refresh later if Java extension is importing your projects.")}

} +
} + {richText(l10n.t("Refresh{0}"), [])}
); diff --git a/src/java-runtime/assets/ToolingJDKPanel.tsx b/src/java-runtime/assets/ToolingJDKPanel.tsx index 99ddd74d..7208492e 100644 --- a/src/java-runtime/assets/ToolingJDKPanel.tsx +++ b/src/java-runtime/assets/ToolingJDKPanel.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import { JavaRuntimeData, ToolingRuntimeInfo } from "../types"; @@ -12,22 +14,22 @@ type Props = ToolingRuntimeInfo & Pick; export function ToolingJDKPanel({ javaHomeError, javaHomeWarning, javaDotHome, toolingJreVersion, requiredJdkVersion, projectJdkError }: Props) { return (
-

Configure Runtime for Language Server

-
Java Language Server requires a JDK {requiredJdkVersion}+ to launch itself. Your projects can use older JDKs.
+

{l10n.t("Configure Runtime for Language Server")}

+
{richText(l10n.t("{0}Java Language Server requires a JDK {1}+ to launch itself. Your projects can use older JDKs."), [, requiredJdkVersion])}
{javaDotHome ? ( -

Language server runtime reported by redhat.java: {javaDotHome} (Java {toolingJreVersion}).

+

{richText(l10n.t("Language server runtime reported by redhat.java: {0} (Java {1})."), [{javaDotHome}, toolingJreVersion])}

) : ( -

Language server runtime information has not been reported by redhat.java.

+

{l10n.t("Language server runtime information has not been reported by redhat.java.")}

)} {javaHomeError && (

{javaHomeError}

)} {javaHomeWarning && (

{javaHomeWarning}

)} {projectJdkError && (

{projectJdkError}

)} -

Open Java Logs for details. Runtime selection and startup diagnostics are provided by redhat.java.

+

{richText(l10n.t("{0} for details. Runtime selection and startup diagnostics are provided by redhat.java."), [{l10n.t("Open Java Logs")}])}

- Refresh + {richText(l10n.t("Refresh{0}"), [])}
); } diff --git a/src/java-runtime/assets/components/DefaultJDKSelector.tsx b/src/java-runtime/assets/components/DefaultJDKSelector.tsx index dbb0ad18..12c3ac44 100644 --- a/src/java-runtime/assets/components/DefaultJDKSelector.tsx +++ b/src/java-runtime/assets/components/DefaultJDKSelector.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import { useState } from "react"; @@ -26,16 +27,12 @@ export function DefaultJDKSelector({ jdkEntries, projectRuntime: p }: Props) { return (
- {isEditing ? - {jdkEntries.map(jdk => ( ))} - - : - {p.sourceLevel} - } - setIsEditing(true)} title="Edit"> + : {p.sourceLevel}} + setIsEditing(true)} title={l10n.t("Edit")}>
); } diff --git a/src/java-runtime/assets/components/JDKActions.tsx b/src/java-runtime/assets/components/JDKActions.tsx index ab52a6ef..6cc97af3 100644 --- a/src/java-runtime/assets/components/JDKActions.tsx +++ b/src/java-runtime/assets/components/JDKActions.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import { useState } from "react"; @@ -21,11 +23,11 @@ export function JDKActions() { return ( <> ); diff --git a/src/java-runtime/assets/components/ProjectTypeHint.tsx b/src/java-runtime/assets/components/ProjectTypeHint.tsx index c36b39e9..679318ad 100644 --- a/src/java-runtime/assets/components/ProjectTypeHint.tsx +++ b/src/java-runtime/assets/components/ProjectTypeHint.tsx @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; +import { richText } from "../../../l10n/richText"; + interface Props { projectType: "Maven" | "Gradle" | "Others" | undefined; } @@ -11,7 +14,7 @@ export function ProjectTypeHint({ projectType }: Props) { case "Maven": return (
-

For projects managed by build tools, Java version is specified in build scripts. E.g. to use Java 8, add below lines in pom.xml:

+

{richText(l10n.t("For projects managed by build tools, Java version is specified in build scripts. E.g. to use Java 8, add below lines in {0}:"), [pom.xml])}

<properties>
@@ -25,7 +28,7 @@ export function ProjectTypeHint({ projectType }: Props) { case "Gradle": return (
-

For projects managed by build tools, Java version is specified in build scripts. E.g. to use Java 8, add below lines in build.gradle:

+

{richText(l10n.t("For projects managed by build tools, Java version is specified in build scripts. E.g. to use Java 8, add below lines in {0}:"), [build.gradle])}

sourceCompatibility = 1.8
@@ -37,7 +40,7 @@ export function ProjectTypeHint({ projectType }: Props) { case "Others": return (
-

For folders containing .java files, but not managed by build tools like Maven/Gradle, a default JDK is used.

+

{l10n.t("For folders containing .java files, but not managed by build tools like Maven/Gradle, a default JDK is used.")}

); default: diff --git a/src/java-runtime/assets/index.ts b/src/java-runtime/assets/index.ts index e87a41a3..6327ea14 100644 --- a/src/java-runtime/assets/index.ts +++ b/src/java-runtime/assets/index.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; + import { createElement } from "react"; import { createRoot } from "react-dom/client"; import "./style.scss"; diff --git a/src/java-runtime/index.ts b/src/java-runtime/index.ts index 83a08772..23b67dbd 100644 --- a/src/java-runtime/index.ts +++ b/src/java-runtime/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap } from "../l10n/host"; import { findRuntimes, getRuntime, IJavaRuntime } from "jdk-utils"; import * as path from "path"; import * as vscode from "vscode"; @@ -19,7 +20,7 @@ export async function javaRuntimeCmdHandler(context: vscode.ExtensionContext, _o return; } - javaRuntimeView = vscode.window.createWebviewPanel("java.runtime", "Configure Java Runtime", { + javaRuntimeView = vscode.window.createWebviewPanel("java.runtime", vscode.l10n.t("Configure Java Runtime"), { viewColumn: vscode.ViewColumn.One, }, { enableScripts: true, @@ -35,6 +36,7 @@ function onDidDisposeWebviewPanel() { } async function initializeJavaRuntimeView(context: vscode.ExtensionContext, webviewPanel: vscode.WebviewPanel, onDisposeCallback: () => void) { + webviewPanel.title = vscode.l10n.t("Configure Java Runtime"); webviewPanel.iconPath = { light: vscode.Uri.file(path.join(context.extensionPath, "caption.light.svg")), dark: vscode.Uri.file(path.join(context.extensionPath, "caption.dark.svg")) @@ -109,16 +111,16 @@ async function initializeJavaRuntimeView(context: vscode.ExtensionContext, webvi canSelectFiles: false, canSelectMany: false, canSelectFolders: true, - title: "Specify Java runtime to launch Language Server" + title: vscode.l10n.t("Specify Java runtime to launch Language Server") }); if (javaHomeUri) { const javaHome = javaHomeUri[0].fsPath; const runtime = await getRuntime(javaHome, {checkJavac: true, withVersion: true}); const requiredJdkVersion = getRequiredJdkVersion(); if (!runtime?.hasJavac) { - await vscode.window.showWarningMessage(`${javaHome} is not a valid JDK home directory.`); + await vscode.window.showWarningMessage(vscode.l10n.t("{0} is not a valid JDK home directory.", javaHome)); } else if (!runtime.version || runtime.version.major < requiredJdkVersion) { - await vscode.window.showWarningMessage(`Java ${requiredJdkVersion} or more recent is required to launch the Java Language Server. "${javaHome}" doesn't meet the requirement.`); + await vscode.window.showWarningMessage(vscode.l10n.t('Java {0} or more recent is required to launch the Java Language Server. "{1}" doesn\'t meet the requirement.', requiredJdkVersion, javaHome)); } else { await vscode.workspace.getConfiguration("java").update("jdt.ls.java.home", javaHome, vscode.ConfigurationTarget.Global); await refreshRuntimes(); @@ -147,7 +149,7 @@ async function initializeJavaRuntimeView(context: vscode.ExtensionContext, webvi console.warn(error); if (!disposed) { const message = error instanceof Error ? error.message : String(error); - await vscode.window.showErrorMessage(`Unable to refresh Configure Java Runtime: ${message}`); + await vscode.window.showErrorMessage(vscode.l10n.t("Unable to refresh Configure Java Runtime: {0}", message)); } } } @@ -176,15 +178,16 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string const cspSource = webviewPanel.webview.cspSource; return ` - + - Configure Java Runtime + ${escapeHtml(vscode.l10n.t("Configure Java Runtime"))} + ${localizationBootstrap(nonce)}
@@ -214,7 +217,7 @@ export async function findJavaRuntimeEntries(): Promise { javaHomes = runtimes.filter(r => r.hasJavac); } } catch (error) { - recordInventoryError(errors, "Unable to list installed project JDKs", error); + recordInventoryError(errors, vscode.l10n.t("Unable to list installed project JDKs"), error); } const javaRuntimes: JavaRuntimeEntry[] = (javaHomes ?? []).map(elem => ({ name: elem.homedir, @@ -245,11 +248,16 @@ interface ProjectRuntimeResult { errors: string[]; } +class RuntimeInventoryError extends Error { + constructor(message: string, readonly localizedMessage: string) { + super(message); + } +} + function recordInventoryError(errors: string[], context: string, error: unknown) { const message = error instanceof Error ? error.message : String(error); - const diagnostic = `${context}: ${message}`; - console.warn(diagnostic, error); - errors.push(diagnostic); + console.warn(`${context}: ${message}`, error); + errors.push(`${context}: ${error instanceof RuntimeInventoryError ? error.localizedMessage : message}`); } async function addProjectRuntime(result: ProjectRuntimeResult, rootPath: string, name?: string) { @@ -263,7 +271,7 @@ async function addProjectRuntime(result: ProjectRuntimeResult, rootPath: string, ...runtimeSpec }); } catch (error) { - recordInventoryError(result.errors, `Unable to read runtime information for project "${name || rootPath}" (${rootPath})`, error); + recordInventoryError(result.errors, vscode.l10n.t('Unable to read runtime information for project "{0}" ({1})', name || rootPath, rootPath), error); } } @@ -281,7 +289,7 @@ async function getProjectRuntimesFromPM(): Promise { await addProjectRuntime(result, project.uri, project.displayName || project.name); } } catch (error) { - recordInventoryError(result.errors, `Unable to list projects from Project Manager for workspace "${folderUri}"`, error); + recordInventoryError(result.errors, vscode.l10n.t('Unable to list projects from Project Manager for workspace "{0}"', folderUri), error); } } } @@ -300,7 +308,7 @@ async function getProjectRuntimesFromLS(): Promise { await addProjectRuntime(result, projectRoot); } } catch (error) { - recordInventoryError(result.errors, "Unable to list projects from the Java language server", error); + recordInventoryError(result.errors, vscode.l10n.t("Unable to list projects from the Java language server"), error); } } return result; @@ -309,7 +317,8 @@ async function getProjectRuntimesFromLS(): Promise { async function getRuntimeSpec(projectRootUri: string) { const javaExt = vscode.extensions.getExtension("redhat.java"); if (!javaExt?.isActive || typeof javaExt.exports?.getProjectSettings !== "function") { - throw new Error("Project settings are not available from redhat.java."); + throw new RuntimeInventoryError("Project settings are not available from redhat.java.", + vscode.l10n.t("Project settings are not available from redhat.java.")); } const NATURE_IDS = "org.eclipse.jdt.ls.core.natureIds"; const SOURCE_LEVEL_KEY = "org.eclipse.jdt.core.compiler.source"; @@ -319,7 +328,8 @@ async function getRuntimeSpec(projectRootUri: string) { ); const natureIds = settings?.[NATURE_IDS]; if (!Array.isArray(natureIds) || !natureIds.every((natureId: unknown) => typeof natureId === "string")) { - throw new Error("Project type information is unavailable."); + throw new RuntimeInventoryError("Project type information is unavailable.", + vscode.l10n.t("Project type information is unavailable.")); } const runtimePath = settings?.[VM_INSTALL_PATH]; const sourceLevel = settings?.[SOURCE_LEVEL_KEY]; diff --git a/src/java-runtime/utils/upstreamApi.ts b/src/java-runtime/utils/upstreamApi.ts index e53dc336..f724764a 100644 --- a/src/java-runtime/utils/upstreamApi.ts +++ b/src/java-runtime/utils/upstreamApi.ts @@ -43,12 +43,12 @@ export function getToolingRuntimeInfo(): ToolingRuntimeInfo { const info: ToolingRuntimeInfo = { requiredJdkVersion }; const javaExt = vscode.extensions.getExtension<{ javaRequirement?: RequirementsData; status?: string }>("redhat.java"); if (!javaExt) { - info.javaHomeWarning = "Language Support for Java (redhat.java) is unavailable. Check that it is installed and enabled."; + info.javaHomeWarning = vscode.l10n.t("Language Support for Java (redhat.java) is unavailable. Check that it is installed and enabled."); return info; } const api = javaExt.isActive ? javaExt.exports : undefined; if (api?.status === "Error") { - info.javaHomeError = "redhat.java reports an error. Open the Java logs for details."; + info.javaHomeError = vscode.l10n.t("redhat.java reports an error. Open the Java logs for details."); } const requirements = api?.javaRequirement; if (!requirements) { @@ -57,7 +57,7 @@ export function getToolingRuntimeInfo(): ToolingRuntimeInfo { info.javaDotHome = requirements.tooling_jre; info.toolingJreVersion = requirements.tooling_jre_version; if (requirements.tooling_jre && requirements.tooling_jre_version < requiredJdkVersion) { - info.javaHomeWarning = `The runtime reported by redhat.java uses Java ${requirements.tooling_jre_version}, below the required Java ${requiredJdkVersion}. Open the Java logs for details.`; + info.javaHomeWarning = vscode.l10n.t("The runtime reported by redhat.java uses Java {0}, below the required Java {1}. Open the Java logs for details.", requirements.tooling_jre_version, requiredJdkVersion); } const configuredHome = vscode.workspace.getConfiguration().get("java.jdt.ls.java.home"); @@ -66,8 +66,8 @@ export function getToolingRuntimeInfo(): ToolingRuntimeInfo { const configuredVersion = sameHome(expandHomeDir(configuredHome), requirements.java_home) ? requirements.java_version : undefined; const configurationWarning = configuredVersion && configuredVersion < requiredJdkVersion - ? `The configured 'java.jdt.ls.java.home' uses Java ${configuredVersion}, below the required Java ${requiredJdkVersion}. redhat.java reports a different language-server runtime.` - : "The configured 'java.jdt.ls.java.home' differs from the runtime reported by redhat.java. Open the Java logs for details."; + ? vscode.l10n.t("The configured 'java.jdt.ls.java.home' uses Java {0}, below the required Java {1}. redhat.java reports a different language-server runtime.", configuredVersion, requiredJdkVersion) + : vscode.l10n.t("The configured 'java.jdt.ls.java.home' differs from the runtime reported by redhat.java. Open the Java logs for details."); info.javaHomeWarning = [info.javaHomeWarning, configurationWarning].filter(Boolean).join(" "); } return info; diff --git a/src/l10n/browser.ts b/src/l10n/browser.ts new file mode 100644 index 00000000..faa21274 --- /dev/null +++ b/src/l10n/browser.ts @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import * as l10n from "@vscode/l10n"; + +interface LocalizationData { + language: string; + bundle: { [key: string]: string }; +} + +export function initializeLocalization(): void { + const element = document.getElementById("java-pack-l10n"); + if (!element) { + l10n.config({ contents: {} }); + return; + } + const data: LocalizationData = JSON.parse(element.textContent || ""); + if (!data || typeof data.language !== "string" || !data.bundle || typeof data.bundle !== "object" || Array.isArray(data.bundle) || + Object.values(data.bundle).some(value => typeof value !== "string")) { + throw new Error("Invalid Java Pack localization bootstrap."); + } + l10n.config({ contents: data.bundle }); + document.documentElement.lang = data.language; +} + +initializeLocalization(); diff --git a/src/l10n/display.ts b/src/l10n/display.ts new file mode 100644 index 00000000..8134be82 --- /dev/null +++ b/src/l10n/display.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import * as l10n from "@vscode/l10n"; +import { ProjectType } from "../utils/webview"; + +export function projectTypeLabel(projectType: ProjectType): string { + switch (projectType) { + case ProjectType.Default: return l10n.t("Default project"); + case ProjectType.UnmanagedFolder: return l10n.t("Unmanaged folder"); + case ProjectType.Maven: return l10n.t("Maven"); + case ProjectType.Gradle: return l10n.t("Gradle"); + case ProjectType.Others: return l10n.t("Others"); + } +} diff --git a/src/l10n/host.ts b/src/l10n/host.ts new file mode 100644 index 00000000..8060fc4b --- /dev/null +++ b/src/l10n/host.ts @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import * as vscode from "vscode"; + +export function escapeHtml(value: string): string { + return value.replace(/[&<>"']/g, character => ({ + "&": "&", "<": "<", ">": ">", '"': """, "'": "'", + }[character]!)); +} + +export function webviewLanguage(): string { + return escapeHtml(vscode.env.language); +} + +export function formatHtml(message: string, trustedFragments: readonly string[]): string { + return escapeHtml(message).replace(/\{(\d+)\}/g, (_match, index: string) => { + const fragment = trustedFragments[Number(index)]; + if (fragment === undefined) { + throw new Error(`Unknown localized HTML placeholder: ${index}`); + } + return fragment; + }); +} + +export function localizationBootstrap(nonce: string): string { + // Keep catalog text inert, including HTML/script delimiters and JS line separators. + const data = JSON.stringify({ language: vscode.env.language, bundle: vscode.l10n.bundle ?? {} }) + .replace(/[<>&\u2028\u2029]/g, character => "\\u" + character.charCodeAt(0).toString(16).padStart(4, "0")); + return ``; +} diff --git a/src/l10n/richText.tsx b/src/l10n/richText.tsx new file mode 100644 index 00000000..2a7106e3 --- /dev/null +++ b/src/l10n/richText.tsx @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +import { Fragment, ReactNode } from "react"; + +export function richText(message: string, nodes: readonly ReactNode[]): ReactNode { + return message.split(/(\{\d+\})/g).map((part, index) => { + const match = /^\{(\d+)\}$/.exec(part); + const nodeIndex = match ? Number(match[1]) : undefined; + if (nodeIndex !== undefined && nodeIndex >= nodes.length) { + throw new Error(`Unknown localized React placeholder: ${nodeIndex}`); + } + return {nodeIndex === undefined ? part : nodes[nodeIndex]}; + }); +} diff --git a/src/overview/assets/index.ts b/src/overview/assets/index.ts index 4af625c5..76acb2ef 100644 --- a/src/overview/assets/index.ts +++ b/src/overview/assets/index.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; + const $ = require("jquery"); import "../../assets/vscode.scss"; import "bootstrap/js/src/tab"; diff --git a/src/overview/index.ts b/src/overview/index.ts index 6a916813..0fe91c5d 100644 --- a/src/overview/index.ts +++ b/src/overview/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap, formatHtml } from "../l10n/host"; import * as vscode from "vscode"; import * as path from "path"; import { instrumentOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; @@ -25,7 +26,7 @@ export async function overviewCmdHandler(context: vscode.ExtensionContext, _oper overviewView = vscode.window.createWebviewPanel( "java.overview", - "Java Overview", + vscode.l10n.t("Java Overview"), { viewColumn: vscode.ViewColumn.One, preserveFocus: showInBackground @@ -47,6 +48,7 @@ function onDidDisposeWebviewPanel() { } async function initializeOverviewView(context: vscode.ExtensionContext, webviewPanel: vscode.WebviewPanel, onDisposeCallback: () => void) { + webviewPanel.title = vscode.l10n.t("Java Overview"); webviewPanel.iconPath = { light: vscode.Uri.file(path.join(context.extensionPath, "caption.light.svg")), dark: vscode.Uri.file(path.join(context.extensionPath, "caption.dark.svg")) @@ -117,82 +119,83 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string const cspSource = webviewPanel.webview.cspSource; return ` - + - Java Overview + ${escapeHtml(vscode.l10n.t("Java Overview"))} + ${localizationBootstrap(nonce)}
-

Java Overview

+

${escapeHtml(vscode.l10n.t("Java Overview"))}

@@ -200,55 +203,55 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
@@ -256,34 +259,34 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string
-

Learn

+

${escapeHtml(vscode.l10n.t("Learn"))}

- -
diff --git a/src/project-settings/assets/classpath/features/ClasspathConfigurationView.tsx b/src/project-settings/assets/classpath/features/ClasspathConfigurationView.tsx index 2de30abe..91a5884e 100644 --- a/src/project-settings/assets/classpath/features/ClasspathConfigurationView.tsx +++ b/src/project-settings/assets/classpath/features/ClasspathConfigurationView.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-tabs/index.js"; import "@vscode-elements/elements/dist/vscode-tab-header/index.js"; import "@vscode-elements/elements/dist/vscode-tab-panel/index.js"; @@ -49,9 +50,9 @@ const ClasspathConfigurationView = (): JSX.Element => { return (
- onClickTab("source")}>Sources - onClickTab("jdk")}>JDK Runtime - onClickTab("libraries")}>Libraries + onClickTab("source")}>{l10n.t("Sources")} + onClickTab("jdk")}>{l10n.t("JDK Runtime")} + onClickTab("libraries")}>{l10n.t("Libraries")} {[ProjectType.Gradle, ProjectType.Maven].includes(projectType) && ()} {projectType !== ProjectType.Gradle && projectType !== ProjectType.Maven && ()} diff --git a/src/project-settings/assets/classpath/features/components/Hint.tsx b/src/project-settings/assets/classpath/features/components/Hint.tsx index bf00fb26..f767f618 100644 --- a/src/project-settings/assets/classpath/features/components/Hint.tsx +++ b/src/project-settings/assets/classpath/features/components/Hint.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { useEffect } from "react"; import { ClasspathEntry, ProjectInfo } from "../../../../types"; import { useSelector } from "react-redux"; @@ -55,12 +57,7 @@ const Hint = (): JSX.Element | null => { return (
- {(projectType[activeProjectIndex] === ProjectType.Gradle || projectType[activeProjectIndex] === ProjectType.Maven) && - - '{projects[activeProjectIndex].name}' is imported by {projectType[activeProjectIndex]}, changes made to the classpath might be lost after reloading. - To make permanent changes, please edit the handleOpenBuildFile()}>{buildFile} file. - - } + {(projectType[activeProjectIndex] === ProjectType.Gradle || projectType[activeProjectIndex] === ProjectType.Maven) && {richText(l10n.t("'{0}' is imported by {1}, changes made to the classpath might be lost after reloading. To make permanent changes, please edit the {2} file."), [projects[activeProjectIndex].name, projectType[activeProjectIndex], handleOpenBuildFile()}>{buildFile}])}}
); }; diff --git a/src/project-settings/assets/classpath/features/components/JdkRuntime.tsx b/src/project-settings/assets/classpath/features/components/JdkRuntime.tsx index 3c8810fa..6c993ea0 100644 --- a/src/project-settings/assets/classpath/features/components/JdkRuntime.tsx +++ b/src/project-settings/assets/classpath/features/components/JdkRuntime.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-divider/index.js"; import "@vscode-elements/elements/dist/vscode-single-select/index.js"; import "@vscode-elements/elements/dist/vscode-option/index.js"; @@ -85,7 +87,7 @@ const JdkRuntime = (): JSX.Element => { return (
- JDK: + {l10n.t("JDK:")} { > {!hasActiveVmInstall && ( - {activeVmInstallPath ? "Current project JDK (not listed)" : "Project JDK not available"} + {activeVmInstallPath ? l10n.t("Current project JDK (not listed)") : l10n.t("Project JDK not available")} )} {vmInstalls.map((vmInstall) => ( @@ -112,21 +114,12 @@ const JdkRuntime = (): JSX.Element => { {activeVmInstallPath}
{!hasActiveVmInstall && activeVmInstallPath && ( -

The current project JDK is not in the available runtime list. Refresh JDKs or locate its installation.

+

{l10n.t("The current project JDK is not in the available runtime list. Refresh JDKs or locate its installation.")}

)}
- ClasspathRequest.onWillListVmInstalls()}> - - Refresh JDKs - - ClasspathRequest.onWillAddNewJdk()}> - - Find a local JDK... - - CommonRequest.onWillExecuteCommand("java.installJdk")}> - - Download a new JDK... - + ClasspathRequest.onWillListVmInstalls()}>{richText(l10n.t("{0}Refresh JDKs"), [])} + ClasspathRequest.onWillAddNewJdk()}>{richText(l10n.t("{0}Find a local JDK..."), [])} + CommonRequest.onWillExecuteCommand("java.installJdk")}>{richText(l10n.t("{0}Download a new JDK..."), [])}
); diff --git a/src/project-settings/assets/classpath/features/components/Libraries.tsx b/src/project-settings/assets/classpath/features/components/Libraries.tsx index c3f81ef4..877bec0c 100644 --- a/src/project-settings/assets/classpath/features/components/Libraries.tsx +++ b/src/project-settings/assets/classpath/features/components/Libraries.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import "@vscode-elements/elements/dist/vscode-divider/index.js"; @@ -104,7 +106,7 @@ const Libraries = (): JSX.Element => { if (libraries.length === 0) { librariesSections = (
- No libraries are configured. + {l10n.t("No libraries are configured.")}
); } else { @@ -115,7 +117,7 @@ const Libraries = (): JSX.Element => { {resolveLibPath(library)}
- handleRemove(index)} title="Remove"> + handleRemove(index)} title={l10n.t("Remove")}>
@@ -127,10 +129,7 @@ const Libraries = (): JSX.Element => {
- handleAdd()}> - - Add Library... - + handleAdd()}>{richText(l10n.t("{0}Add Library..."), [])}
diff --git a/src/project-settings/assets/classpath/features/components/Output.tsx b/src/project-settings/assets/classpath/features/components/Output.tsx index 7facaf49..d6de0ac0 100644 --- a/src/project-settings/assets/classpath/features/components/Output.tsx +++ b/src/project-settings/assets/classpath/features/components/Output.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import "@vscode-elements/elements/dist/vscode-textfield/index.js"; @@ -47,12 +48,12 @@ const Output = (): JSX.Element | null => { return (
-

Output Path

+

{l10n.t("Output Path")}

- handleClick()}> + placeholder={l10n.t("Output Path")}> + handleClick()}> diff --git a/src/project-settings/assets/classpath/features/components/Sources.tsx b/src/project-settings/assets/classpath/features/components/Sources.tsx index 66fa7251..f101d55e 100644 --- a/src/project-settings/assets/classpath/features/components/Sources.tsx +++ b/src/project-settings/assets/classpath/features/components/Sources.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import "@vscode-elements/elements/dist/vscode-textfield/index.js"; import "@vscode-elements/elements/dist/vscode-divider/index.js"; @@ -154,36 +156,36 @@ const Sources = (): JSX.Element => { return (
- +
+ placeholder={l10n.t("Source Root Path")}> - handleBrowse("source")}> + handleBrowse("source")}>
- +
+ placeholder={l10n.t("Output Path")}> - handleBrowse("output")}> + handleBrowse("output")}>
- handleOK()}>OK - handleCancel()}>Cancel + handleOK()}>{l10n.t("OK")} + handleCancel()}>{l10n.t("Cancel")}
); @@ -205,10 +207,10 @@ const Sources = (): JSX.Element => {
{source.output || defaultOutput}
- handleEdit(source.path, source.output || defaultOutput, index)} title="Edit"> + handleEdit(source.path, source.output || defaultOutput, index)} title={l10n.t("Edit")}> - handleRemove(source.path)} title="Remove"> + handleRemove(source.path)} title={l10n.t("Remove")}>
@@ -220,19 +222,16 @@ const Sources = (): JSX.Element => { return (
- handleAdd()}> - - Add Source Root... - + handleAdd()}>{richText(l10n.t("{0}Add Source Root..."), [])}
-
Path
-
Output
+
{l10n.t("Path")}
+
{l10n.t("Output")}
{sources.length === 0 ? ( -
No source paths are configured.
+
{l10n.t("No source paths are configured.")}
) : ( sources.map((source, index) => renderSourceRow(source, index)) )} diff --git a/src/project-settings/assets/classpath/features/components/UnmanagedFolderSources.tsx b/src/project-settings/assets/classpath/features/components/UnmanagedFolderSources.tsx index efe2026a..cca9c97b 100644 --- a/src/project-settings/assets/classpath/features/components/UnmanagedFolderSources.tsx +++ b/src/project-settings/assets/classpath/features/components/UnmanagedFolderSources.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import "@vscode-elements/elements/dist/vscode-divider/index.js"; @@ -68,7 +70,7 @@ const UnmanagedFolderSources = (): JSX.Element => { if (sources.length === 0) { sourceSections = (
- No source paths are configured. + {l10n.t("No source paths are configured.")}
); } else { @@ -79,7 +81,7 @@ const UnmanagedFolderSources = (): JSX.Element => { {source.path}
- handleRemove(source.path)} title="Remove"> + handleRemove(source.path)} title={l10n.t("Remove")}>
@@ -89,12 +91,9 @@ const UnmanagedFolderSources = (): JSX.Element => { return (
-

Source Paths

+

{l10n.t("Source Paths")}

- handleAdd()}> - - Add Source Root... - + handleAdd()}>{richText(l10n.t("{0}Add Source Root..."), [])}
diff --git a/src/project-settings/assets/compiler/features/CompilerConfigurationView.tsx b/src/project-settings/assets/compiler/features/CompilerConfigurationView.tsx index fa60a71f..aabf16f8 100644 --- a/src/project-settings/assets/compiler/features/CompilerConfigurationView.tsx +++ b/src/project-settings/assets/compiler/features/CompilerConfigurationView.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-divider/index.js"; import "@vscode-elements/elements/dist/vscode-single-select/index.js"; import "@vscode-elements/elements/dist/vscode-option/index.js"; @@ -183,14 +185,14 @@ const CompilerConfigurationView = (): JSX.Element | null => {
- Use '--release' option for cross-compilation (Java 9 and later) + {l10n.t("Use '--release' option for cross-compilation (Java 9 and later)")}
- Bytecode version: + {l10n.t("Bytecode version:")} @@ -200,7 +202,7 @@ const CompilerConfigurationView = (): JSX.Element | null => { - Source compatibility: + {l10n.t("Source compatibility:")} @@ -210,7 +212,7 @@ const CompilerConfigurationView = (): JSX.Element | null => { - Target compatibility: + {l10n.t("Target compatibility:")} @@ -222,25 +224,21 @@ const CompilerConfigurationView = (): JSX.Element | null => {
- - Target compatibility must be equal or greater than source compatibility. - + {l10n.t("Target compatibility must be equal or greater than source compatibility.")}
- - Please make sure to have a compatible JDK configured (currently {currentJdkComplianceLevel}). You can change the JDK under the onClickChangeJdk()}>JDK Runtime tab. - + {richText(l10n.t("Please make sure to have a compatible JDK configured (currently {0}). You can change the JDK under the {1} tab."), [currentJdkComplianceLevel, onClickChangeJdk()}>{l10n.t("JDK Runtime")}])}
- Enable preview features + {l10n.t("Enable preview features")}
-

Class File Generation

+

{l10n.t("Class File Generation")}

- Generate debugging information + {l10n.t("Generate debugging information")}
- Store information about method parameters + {l10n.t("Store information about method parameters")}
diff --git a/src/project-settings/assets/compiler/features/components/Hint.tsx b/src/project-settings/assets/compiler/features/components/Hint.tsx index 84607bc0..81f8225d 100644 --- a/src/project-settings/assets/compiler/features/components/Hint.tsx +++ b/src/project-settings/assets/compiler/features/components/Hint.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { useSelector } from "react-redux"; import { ProjectType } from "../../../../../utils/webview"; import { ClasspathRequest } from "../../../vscode/utils"; @@ -39,14 +41,9 @@ const Hint = (): JSX.Element | null => { return (
- {(projectType[activeProjectIndex] === ProjectType.Gradle || projectType[activeProjectIndex] === ProjectType.Maven) && -
- - '{projects[activeProjectIndex].name}' is imported by {projectType[activeProjectIndex]}, some changes made to the compiler settings might be lost after reloading. - To make permanent changes, please edit the handleOpenBuildFile()}>{buildFile} file. - -
- } + {(projectType[activeProjectIndex] === ProjectType.Gradle || projectType[activeProjectIndex] === ProjectType.Maven) &&
+ {richText(l10n.t("'{0}' is imported by {1}, some changes made to the compiler settings might be lost after reloading. To make permanent changes, please edit the {2} file."), [projects[activeProjectIndex].name, projectType[activeProjectIndex], handleOpenBuildFile()}>{buildFile}])} +
}
); }; diff --git a/src/project-settings/assets/index.tsx b/src/project-settings/assets/index.tsx index c25756a5..30ce0f9a 100644 --- a/src/project-settings/assets/index.tsx +++ b/src/project-settings/assets/index.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; + import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./mainpage/features/App"; diff --git a/src/project-settings/assets/mainpage/features/component/Exception.tsx b/src/project-settings/assets/mainpage/features/component/Exception.tsx index 1ba6ded4..8d3f39f9 100644 --- a/src/project-settings/assets/mainpage/features/component/Exception.tsx +++ b/src/project-settings/assets/mainpage/features/component/Exception.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { useSelector } from "react-redux"; import { encodeCommandUriWithTelemetry, supportedByNavigator } from "../../../../../utils/webview"; import { ProjectSettingsException } from "../../../../types"; @@ -17,17 +19,17 @@ const Exception = (): JSX.Element | null => { command = "workbench.action.files.openFileFolder"; } content = ( - There are no Java projects opened in the current workspace. Please try to reload the page or open a Java project. + {richText(l10n.t("There are no Java projects opened in the current workspace. Please try to {0} or {1}."), [{l10n.t("reload the page")}, {l10n.t("open a Java project")}])} ); break; case ProjectSettingsException.JavaExtensionNotInstalled: content = ( - The required extension Language Support for Java™ by Red Hat is not installed or it's disabled. Please install it in Visual Studio Code and reload the page after installation. + {richText(l10n.t("The required extension {0} is not installed or it's disabled. Please {1} it in Visual Studio Code and {2} the page after installation."), [{l10n.t("Language Support for Java™ by Red Hat")}, {l10n.t("install")}, {l10n.t("reload")}])} ); break; case ProjectSettingsException.StaleJavaExtension: content = ( - The version of required extension Language Support for Java™ by Red Hat is too stale. Please update it and reload the page. + {richText(l10n.t("The version of required extension {0} is too stale. Please {1} it and {2} the page."), [{l10n.t("Language Support for Java™ by Red Hat")}, {l10n.t("update")}, {l10n.t("reload")}])} ); break; default: diff --git a/src/project-settings/assets/mainpage/features/component/Footer.tsx b/src/project-settings/assets/mainpage/features/component/Footer.tsx index e92a9b37..b34d725b 100644 --- a/src/project-settings/assets/mainpage/features/component/Footer.tsx +++ b/src/project-settings/assets/mainpage/features/component/Footer.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-button/index.js"; import { Dispatch } from "@reduxjs/toolkit"; @@ -144,16 +145,12 @@ const Footer = (): JSX.Element => { return ( ); }; diff --git a/src/project-settings/assets/mainpage/features/component/ProjectSelector.tsx b/src/project-settings/assets/mainpage/features/component/ProjectSelector.tsx index 085627ce..b09c9184 100644 --- a/src/project-settings/assets/mainpage/features/component/ProjectSelector.tsx +++ b/src/project-settings/assets/mainpage/features/component/ProjectSelector.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-single-select/index.js"; import "@vscode-elements/elements/dist/vscode-option/index.js"; @@ -79,7 +80,7 @@ const ProjectSelector = (): JSX.Element | null => { return (
- Project: + {l10n.t("Project:")} {projectSelections} diff --git a/src/project-settings/assets/mainpage/features/component/SideBar.tsx b/src/project-settings/assets/mainpage/features/component/SideBar.tsx index 1a5e5d7f..56230ca9 100644 --- a/src/project-settings/assets/mainpage/features/component/SideBar.tsx +++ b/src/project-settings/assets/mainpage/features/component/SideBar.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { useSelector, useDispatch } from "react-redux"; import { Dispatch } from "@reduxjs/toolkit"; import { updateActiveSection } from "../commonSlice"; @@ -28,22 +30,12 @@ const SideBar = (): JSX.Element => {
-
onClickNavBarItem(SectionId.Classpath)}> - Classpath -
-
onClickNavBarItem(SectionId.Compiler)}> - Compiler -
- { - projectType === ProjectType.Maven && ( -
onClickNavBarItem(SectionId.Maven)}> - Maven -
- ) - } -
onClickNavBarItem(SectionId.Formatter)}> - Formatter -
+
onClickNavBarItem(SectionId.Classpath)}>{l10n.t("Classpath")}
+
onClickNavBarItem(SectionId.Compiler)}>{l10n.t("Compiler")}
+ {projectType === ProjectType.Maven && ( +
onClickNavBarItem(SectionId.Maven)}>{l10n.t("Maven")}
+ )} +
onClickNavBarItem(SectionId.Formatter)}>{richText(l10n.t("Formatter {0}"), [])}
diff --git a/src/project-settings/assets/maven/features/MavenConfigurationView.tsx b/src/project-settings/assets/maven/features/MavenConfigurationView.tsx index 6d7b28d0..72b5d2b9 100644 --- a/src/project-settings/assets/maven/features/MavenConfigurationView.tsx +++ b/src/project-settings/assets/maven/features/MavenConfigurationView.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import { useSelector } from "react-redux"; import { ProjectType } from "../../../../utils/webview"; import Profile from "./components/Profile"; @@ -13,7 +14,7 @@ const MavenConfigurationView = (): JSX.Element | null => { } if (projectTypes[activeProjectIndex] !== ProjectType.Maven) { - return Not a Maven project; + return {l10n.t("Not a Maven project")}; } else { return ; } diff --git a/src/project-settings/assets/maven/features/components/Profile.tsx b/src/project-settings/assets/maven/features/components/Profile.tsx index e9992c52..e06a15f7 100644 --- a/src/project-settings/assets/maven/features/components/Profile.tsx +++ b/src/project-settings/assets/maven/features/components/Profile.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import "@vscode-elements/elements/dist/vscode-textfield/index.js"; @@ -24,8 +25,8 @@ const Profile = (): JSX.Element => { return (
-

Active Maven Profiles

- (comma separated) +

{l10n.t("Active Maven Profiles")}

+ {l10n.t("(comma separated)")}
{ const sourceFolder: vscode.Uri[] | undefined = await vscode.window.showOpenDialog({ defaultUri: vscode.workspace.workspaceFolders?.[0].uri, - openLabel: "Select Source Folder", + openLabel: vscode.l10n.t("Select Source Folder"), canSelectFiles: false, canSelectFolders: true, canSelectMany: false, @@ -136,7 +136,7 @@ export class ClasspathRequestHandler implements vscode.Disposable { let relativePath: string = path.relative(projectRootPath, sourceFolderPath); if (relativePath.startsWith("..")) { const err: Error = new Error("The source path must be contained in the project root folder."); - vscode.window.showErrorMessage(err.message); + vscode.window.showErrorMessage(vscode.l10n.t("The source path must be contained in the project root folder.")); setUserError(err); throw (err); } @@ -155,7 +155,7 @@ export class ClasspathRequestHandler implements vscode.Disposable { } const sourcePaths: string[] = vscode.workspace.getConfiguration("java", currentProjectRoot).get("project.sourcePaths") || []; if (sourcePaths.includes(relativePath)) { - vscode.window.showInformationMessage(`The path ${relativePath} has already been a source path.`); + vscode.window.showInformationMessage(vscode.l10n.t("The path {0} has already been a source path.", relativePath)); return; } sourcePaths.push(relativePath); @@ -219,8 +219,9 @@ export class ClasspathRequestHandler implements vscode.Disposable { } } catch (error) { const err: Error = new Error(`Failed to update classpaths: ${error}`); - vscode.window.showErrorMessage(err.message, "Open Log Files").then((choice) => { - if (choice === "Open Log Files") { + const openLogs = { title: vscode.l10n.t("Open Log Files") }; + vscode.window.showErrorMessage(vscode.l10n.t("Failed to update classpaths: {0}", String(error)), openLogs).then((choice) => { + if (choice === openLogs) { vscode.commands.executeCommand("java.open.logs"); } }); @@ -237,7 +238,7 @@ export class ClasspathRequestHandler implements vscode.Disposable { private selectOutputPath = instrumentOperation("projectSettings.classpath.selectOutputPath", async (_operationId: string, currentProjectRoot: vscode.Uri) => { const outputFolder: vscode.Uri[] | undefined = await vscode.window.showOpenDialog({ defaultUri: vscode.workspace.workspaceFolders?.[0].uri, - openLabel: "Select Output Folder", + openLabel: vscode.l10n.t("Select Output Folder"), canSelectFiles: false, canSelectFolders: true, canSelectMany: false, @@ -248,13 +249,13 @@ export class ClasspathRequestHandler implements vscode.Disposable { const outputRelativePath: string = path.relative(projectRootPath, outputFullPath); if (outputRelativePath.startsWith("..")) { const err: Error = new Error("The customized output path must be contained in the project root folder."); - vscode.window.showErrorMessage(err.message); + vscode.window.showErrorMessage(vscode.l10n.t("The customized output path must be contained in the project root folder.")); setUserError(err); throw (err); } if (!outputRelativePath) { const err: Error = new Error("Cannot set the project root path as the output path."); - vscode.window.showErrorMessage(err.message); + vscode.window.showErrorMessage(vscode.l10n.t("Cannot set the project root path as the output path.")); setUserError(err); throw (err); } @@ -272,8 +273,10 @@ export class ClasspathRequestHandler implements vscode.Disposable { const outputFullPath = path.join(currentProjectRoot.fsPath, outputRelativePath); if ((await fse.readdir(outputFullPath)).length) { - const choice: string | undefined = await vscode.window.showInformationMessage(`The contents in ${outputFullPath} will be removed, are you sure to continue?`, "Yes", "No"); - if (choice === "Yes") { + const yes = { title: vscode.l10n.t("Yes") }; + const no = { title: vscode.l10n.t("No") }; + const choice = await vscode.window.showInformationMessage(vscode.l10n.t("The contents in {0} will be removed, are you sure to continue?", outputFullPath), yes, no); + if (choice === yes) { await fse.remove(outputFullPath); await fse.ensureDir(outputFullPath); } else { @@ -297,10 +300,10 @@ export class ClasspathRequestHandler implements vscode.Disposable { }; const javaHome: vscode.Uri[] | undefined = await vscode.window.showOpenDialog({ defaultUri: vscode.workspace.workspaceFolders?.[0].uri, - openLabel: "Select JDK Home", + openLabel: vscode.l10n.t("Select JDK Home"), canSelectFiles: false, canSelectFolders: true, - title: "Select the installation path of the JDK" + title: vscode.l10n.t("Select the installation path of the JDK") }); if (!javaHome) { return; @@ -327,7 +330,7 @@ export class ClasspathRequestHandler implements vscode.Disposable { vmInstalls, }); } else { - vscode.window.showErrorMessage(result.message); + vscode.window.showErrorMessage(vscode.l10n.t("Unable to update the project JDK: {0}", result.message)); const err: Error = new Error(result.message); setUserError(err); throw (err); @@ -359,7 +362,7 @@ export class ClasspathRequestHandler implements vscode.Disposable { vmInstalls, }); } else { - vscode.window.showErrorMessage(result.message); + vscode.window.showErrorMessage(vscode.l10n.t("Unable to update the project JDK: {0}", result.message)); const err: Error = new Error(result.message); setUserError(err); throw (err); @@ -369,12 +372,12 @@ export class ClasspathRequestHandler implements vscode.Disposable { private selectLibraries = instrumentOperation("projectSettings.classpath.selectLibraries", async (_operationId: string, currentProjectRoot: vscode.Uri, projectType: unknown) => { const jarFiles: vscode.Uri[] | undefined = await vscode.window.showOpenDialog({ defaultUri: vscode.workspace.workspaceFolders?.[0].uri, - openLabel: "Select Jar File", + openLabel: vscode.l10n.t("Select Jar File"), canSelectFiles: true, canSelectFolders: false, canSelectMany: true, filters: { - "Jar": ["jar"], + [vscode.l10n.t("Jar")]: ["jar"], }, }); if (jarFiles) { @@ -431,7 +434,7 @@ export class ClasspathRequestHandler implements vscode.Disposable { if (!configurationPath) { const err: Error = new Error(`The configuration file: '${configurationPath}' does not exist.`); - vscode.window.showErrorMessage(err.message); + vscode.window.showErrorMessage(vscode.l10n.t("The configuration file: '{0}' does not exist.", configurationPath)); throw (err); } vscode.commands.executeCommand("vscode.open", vscode.Uri.file(configurationPath)); @@ -454,7 +457,7 @@ export class ClasspathRequestHandler implements vscode.Disposable { } const err = error instanceof Error ? error : new Error(String(error)); sendError(err); - void vscode.window.showErrorMessage(`Unable to load Java runtimes: ${err.message}`); + void vscode.window.showErrorMessage(vscode.l10n.t("Unable to load Java runtimes: {0}", err.message)); return undefined; } } diff --git a/src/project-settings/handlers/CompilerRequestHandler.ts b/src/project-settings/handlers/CompilerRequestHandler.ts index af56120b..889aa8e3 100644 --- a/src/project-settings/handlers/CompilerRequestHandler.ts +++ b/src/project-settings/handlers/CompilerRequestHandler.ts @@ -126,7 +126,7 @@ export class CompilerRequestHandler implements vscode.Disposable { const packageJson = vscode.extensions.getExtension("redhat.java")?.packageJSON; if (!packageJson) { const errorString = "The required extension 'redhat.java' is not installed."; - vscode.window.showErrorMessage(errorString); + vscode.window.showErrorMessage(vscode.l10n.t("The required extension 'redhat.java' is not installed.")); const err: Error = new Error(errorString); setUserError(err); sendError(err); diff --git a/src/project-settings/projectSettingsView.ts b/src/project-settings/projectSettingsView.ts index b14fb424..42a0dbf4 100644 --- a/src/project-settings/projectSettingsView.ts +++ b/src/project-settings/projectSettingsView.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap } from "../l10n/host"; import * as path from "path"; import * as vscode from "vscode"; import { instrumentOperation, sendError, sendInfo, setUserError } from "vscode-extension-telemetry-wrapper"; @@ -26,7 +27,7 @@ class ProjectSettingView { if (!projectSettingsPanel) { projectSettingsPanel = vscode.window.createWebviewPanel( "java.projectSettings", - "Project Settings", + vscode.l10n.t("Project Settings"), vscode.ViewColumn.Active, { retainContextWhenHidden: true @@ -60,6 +61,7 @@ class ProjectSettingView { return; } + projectSettingsPanel.title = vscode.l10n.t("Project Settings"); projectSettingsPanel.webview.options = { enableScripts: true, enableCommandUris: true, @@ -197,15 +199,16 @@ class ProjectSettingView { const nonce = getNonce(); const cspSource = webview.cspSource; return ` - + - Project Settings + ${escapeHtml(vscode.l10n.t("Project Settings"))} + ${localizationBootstrap(nonce)}
diff --git a/src/providers/CodeActionProvider.ts b/src/providers/CodeActionProvider.ts index 09b2370e..5116f919 100644 --- a/src/providers/CodeActionProvider.ts +++ b/src/providers/CodeActionProvider.ts @@ -18,10 +18,10 @@ export class CodeActionProvider implements vscode.CodeActionProvider { return []; } - const codeAction: vscode.CodeAction = new vscode.CodeAction("Configure classpath"); + const codeAction: vscode.CodeAction = new vscode.CodeAction(vscode.l10n.t("Configure classpath")); codeAction.diagnostics = classPathDiagnostics; codeAction.command = { - title: "Configure classpath", + title: vscode.l10n.t("Configure classpath"), command: "java.classpathConfiguration" }; codeAction.kind = vscode.CodeActionKind.QuickFix; diff --git a/src/recommendation/xml.ts b/src/recommendation/xml.ts index 59afd7b7..0130b4c4 100644 --- a/src/recommendation/xml.ts +++ b/src/recommendation/xml.ts @@ -5,7 +5,7 @@ import * as vscode from "vscode"; import { extensionRecommendationHandler } from "./handler"; const EXTENSION_NAME = "redhat.vscode-xml"; -const RECOMMENDATION_MESSAGE = "XML extension is recommended to check the syntax when editing pom.xml."; +const recommendationMessage = () => vscode.l10n.t("XML extension is recommended to check the syntax when editing pom.xml."); function isPomDotXml(uri: vscode.Uri) { return !!uri.path && uri.path.toLowerCase().endsWith("pom.xml"); @@ -14,12 +14,12 @@ function isPomDotXml(uri: vscode.Uri) { export function initialize (context: vscode.ExtensionContext) { context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(e => { if (isPomDotXml(e.uri)) { - extensionRecommendationHandler(context, EXTENSION_NAME, RECOMMENDATION_MESSAGE); + extensionRecommendationHandler(context, EXTENSION_NAME, recommendationMessage()); } })); let isPomDotXmlOpened = vscode.workspace.textDocuments.findIndex(doc => isPomDotXml(doc.uri)) !== -1; if (isPomDotXmlOpened) { - extensionRecommendationHandler(context, EXTENSION_NAME, RECOMMENDATION_MESSAGE); + extensionRecommendationHandler(context, EXTENSION_NAME, recommendationMessage()); } } diff --git a/src/utils/index.ts b/src/utils/index.ts index 4e586849..a86a6cdc 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -28,7 +28,7 @@ export function isExtensionInstalled(extName: string) { } export async function recommendExtension(extName: string, message: string): Promise { - const action = "Install"; + const action = { title: vscode.l10n.t("Install") }; const answer = await vscode.window.showInformationMessage(message, action); if (answer === action) { await vscode.commands.executeCommand("java.helper.installExtension", extName, extName); diff --git a/src/welcome/assets/components/ControllerPanel.tsx b/src/welcome/assets/components/ControllerPanel.tsx index 37a56dce..a9cdbf2e 100644 --- a/src/welcome/assets/components/ControllerPanel.tsx +++ b/src/welcome/assets/components/ControllerPanel.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { setWelcomeVisibility } from "../utils"; interface ControllerPanelProps { @@ -10,14 +12,11 @@ interface ControllerPanelProps { export default function ControllerPanel({ showWhenUsingJava }: ControllerPanelProps) { return (
- + />])}
); } diff --git a/src/welcome/assets/components/Header.tsx b/src/welcome/assets/components/Header.tsx index 3d1cb6e7..6ea0f286 100644 --- a/src/welcome/assets/components/Header.tsx +++ b/src/welcome/assets/components/Header.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { encodeCommandUriWithTelemetry } from "../../../utils/webview"; import { WEBVIEW_ID } from "../utils"; @@ -8,9 +10,9 @@ const DEV_BLOG_LINK = "https://devblogs.microsoft.com/?s=Java+on+Visual+Studio+C export default function Header() { const openBlogCommand = encodeCommandUriWithTelemetry(WEBVIEW_ID, "blogs", "java.helper.openUrl", [DEV_BLOG_LINK]); - const title =

Java Help Center

; - const blogsLink = blogs; - const subtitle = Check our {blogsLink} to see what's new; + const title =

{l10n.t("Java Help Center")}

; + const blogsLink = {l10n.t("blogs")}; + const subtitle = {richText(l10n.t("Check our {0} to see what's new"), [blogsLink])}; return (
diff --git a/src/welcome/assets/components/NavigationPanel.tsx b/src/welcome/assets/components/NavigationPanel.tsx index ffa0611f..6ca4ab7f 100644 --- a/src/welcome/assets/components/NavigationPanel.tsx +++ b/src/welcome/assets/components/NavigationPanel.tsx @@ -2,6 +2,7 @@ // Licensed under the MIT license. import { useState, useRef } from "react"; +import * as l10n from "@vscode/l10n"; import { reportTabSwitch, WEBVIEW_ID } from "../utils"; import { encodeCommandUriWithTelemetry } from "../../../utils/webview"; @@ -12,33 +13,36 @@ interface NavigationPanelProps { const groups = [ { name: "General", + label: () => l10n.t("General"), iconClass: "codicon codicon-gear", actions: [ - { name: "Configure Java Runtime", command: "java.runtime" }, - { name: "Open Java Settings", command: "workbench.action.openSettings", args: ["java."] as string[] }, - { name: "Install Extensions...", command: "java.extGuide" }, - { name: "Configure Formatter Settings", command: "java.formatterSettings" } + { name: "Configure Java Runtime", label: () => l10n.t("Configure Java Runtime"), command: "java.runtime" }, + { name: "Open Java Settings", label: () => l10n.t("Open Java Settings"), command: "workbench.action.openSettings", args: ["java."] as string[] }, + { name: "Install Extensions...", label: () => l10n.t("Install Extensions..."), command: "java.extGuide" }, + { name: "Configure Formatter Settings", label: () => l10n.t("Configure Formatter Settings"), command: "java.formatterSettings" } ] }, { name: "Spring", + label: () => l10n.t("Spring"), iconClass: "codicon codicon-globe", actions: [ - { name: "Spring Boot with VS Code", command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-spring-boot"] }, - { name: "Spring PetClinic Sample Application", command: "java.helper.openUrl", args: ["https://github.com/spring-projects/spring-petclinic"] }, - { name: "Install Spring Boot Extension Pack ...", command: "java.helper.installExtension", args: ["vmware.vscode-boot-dev-pack", "Spring Boot Extension Pack"] } + { name: "Spring Boot with VS Code", label: () => l10n.t("Spring Boot with VS Code"), command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-spring-boot"] }, + { name: "Spring PetClinic Sample Application", label: () => l10n.t("Spring PetClinic Sample Application"), command: "java.helper.openUrl", args: ["https://github.com/spring-projects/spring-petclinic"] }, + { name: "Install Spring Boot Extension Pack ...", label: () => l10n.t("Install Spring Boot Extension Pack ..."), command: "java.helper.installExtension", args: ["vmware.vscode-boot-dev-pack", "Spring Boot Extension Pack"] } ] }, { name: "Student", + label: () => l10n.t("Student"), iconClass: "codicon codicon-mortar-board", actions: [ - { name: "Coding and Debugging Tips", command: "java.gettingStarted" }, - { name: "Tutorial: Running and Debugging", command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-debugging"] }, - { name: "Tutorial: Testing", command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-testing"] }, - { name: "Configure Sources, Dependencies, Output Folder...", command: "java.classpathConfiguration" }, - { name: "Quick Start: Jupyter Notebook for Java", command: "java.helper.openUrl", args: ["https://github.com/microsoft/vscode-java-pack/wiki/Quick-Start:-Jupyter-Notebook-for-Java"] }, - { name: "Enable AWT Development", command: "java.toggleAwtDevelopment", args: [true] as any[] }, + { name: "Coding and Debugging Tips", label: () => l10n.t("Coding and Debugging Tips"), command: "java.gettingStarted" }, + { name: "Tutorial: Running and Debugging", label: () => l10n.t("Tutorial: Running and Debugging"), command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-debugging"] }, + { name: "Tutorial: Testing", label: () => l10n.t("Tutorial: Testing"), command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-testing"] }, + { name: "Configure Sources, Dependencies, Output Folder...", label: () => l10n.t("Configure Sources, Dependencies, Output Folder..."), command: "java.classpathConfiguration" }, + { name: "Quick Start: Jupyter Notebook for Java", label: () => l10n.t("Quick Start: Jupyter Notebook for Java"), command: "java.helper.openUrl", args: ["https://github.com/microsoft/vscode-java-pack/wiki/Quick-Start:-Jupyter-Notebook-for-Java"] }, + { name: "Enable AWT Development", label: () => l10n.t("Enable AWT Development"), command: "java.toggleAwtDevelopment", args: [true] as any[] }, ] }, ]; @@ -56,6 +60,7 @@ export default function NavigationPanel({ isAwtDisabled }: NavigationPanelProps) return { ...action, name: `${isAwtDisabled ? "Enable" : "Disable"} AWT Development`, + label: () => isAwtDisabled ? l10n.t("Enable AWT Development") : l10n.t("Disable AWT Development"), args: [isAwtDisabled], }; }), @@ -80,7 +85,7 @@ export default function NavigationPanel({ isAwtDisabled }: NavigationPanelProps) aria-selected={activeTab === group.name} >
- {group.name} + {group.label()}
@@ -94,7 +99,7 @@ export default function NavigationPanel({ isAwtDisabled }: NavigationPanelProps) {action.name} + > {action.label()} ))}
diff --git a/src/welcome/assets/components/QuickActionPanel.tsx b/src/welcome/assets/components/QuickActionPanel.tsx index 32791576..c925ea8b 100644 --- a/src/welcome/assets/components/QuickActionPanel.tsx +++ b/src/welcome/assets/components/QuickActionPanel.tsx @@ -1,22 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { encodeCommandUriWithTelemetry, supportedByNavigator } from "../../../utils/webview"; import { WEBVIEW_ID } from "../utils"; export default function QuickActionPanel() { - const newProjectElement = - {"Create a "} - {"New Project"} - ; - const existingProjectElement = - {"Open an "} - {"Existing Project"} - ; - const tourElement = - {"Take a "} - {"Tour"} - ; + const newProjectElement = {richText(l10n.t("Create a {0}"), [{l10n.t("New Project")}])}; + const existingProjectElement = {richText(l10n.t("Open an {0}"), [{l10n.t("Existing Project")}])}; + const tourElement = {richText(l10n.t("Take a {0}"), [{l10n.t("Tour")}])}; const actions: any[] = [ { name: "Create a New Project", command: "java.project.create", element: newProjectElement }, { name: "Open an Existing Project", command: "workbench.action.files.openFolder", os: "win", element: existingProjectElement }, @@ -33,7 +26,7 @@ export default function QuickActionPanel() { )); return (
-
Get Started
+
{l10n.t("Get Started")}
{actionItems}
diff --git a/src/welcome/assets/components/SocialMediaPanel.tsx b/src/welcome/assets/components/SocialMediaPanel.tsx index 54a32e06..87499a72 100644 --- a/src/welcome/assets/components/SocialMediaPanel.tsx +++ b/src/welcome/assets/components/SocialMediaPanel.tsx @@ -1,19 +1,20 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import * as l10n from "@vscode/l10n"; import { encodeCommandUriWithTelemetry } from "../../../utils/webview"; import { WEBVIEW_ID } from "../utils"; export default function SocialMediaPanel() { const links = [ - { name: "Documentation", command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-tutorial"], iconClass: "codicon codicon-book" }, - { name: "Questions & Issues", command: "java.helper.openUrl", args: ["https://github.com/microsoft/vscode-java-pack/issues"], iconClass: "codicon codicon-github-inverted" }, + { name: "Documentation", label: l10n.t("Documentation"), command: "java.helper.openUrl", args: ["https://code.visualstudio.com/docs/java/java-tutorial"], iconClass: "codicon codicon-book" }, + { name: "Questions & Issues", label: l10n.t("Questions & Issues"), command: "java.helper.openUrl", args: ["https://github.com/microsoft/vscode-java-pack/issues"], iconClass: "codicon codicon-github-inverted" }, ]; const elements = links.map(link => ( {link.name} + > {link.label} )); return (
diff --git a/src/welcome/assets/components/TourPage.tsx b/src/welcome/assets/components/TourPage.tsx index cd5e0353..2a894ce5 100644 --- a/src/welcome/assets/components/TourPage.tsx +++ b/src/welcome/assets/components/TourPage.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { richText } from "../../../l10n/richText"; +import * as l10n from "@vscode/l10n"; import { useState, useEffect, useRef, useMemo } from "react"; import { encodeCommandUriWithTelemetry, supportedByNavigator } from "../../../utils/webview"; import { onWillFetchInitProps, reportSkipTour, WEBVIEW_ID } from "../utils"; @@ -20,19 +22,23 @@ export default function TourPage() { return [{ title: "Open Project Folder", - description:
Open a folder containing your Java project for full features.
, + label: l10n.t("Open Project Folder"), + description:
{richText(l10n.t("{0} containing your Java project for full features."), [{l10n.t("Open a folder")}])}
, imageUri: require("../resources/open-project.png") }, { title: "Project Explorer", - description:
Expand Java Project Explorer to view your project structure.
, + label: l10n.t("Project Explorer"), + description:
{richText(l10n.t("Expand {0} to view your project structure."), [{l10n.t("Java Project Explorer")}])}
, imageUri: require("../resources/project-manager.png") }, { title: "Running and Debugging", - description:
Open Run and Debug View to start your project.
, + label: l10n.t("Running and Debugging"), + description:
{richText(l10n.t("Open {0} to start your project."), [{l10n.t("Run and Debug View")}])}
, imageUri: require("../resources/debugger.png") }, { title: "Testing", - description:
Use Testing View to run unit tests.
, + label: l10n.t("Testing"), + description:
{richText(l10n.t("Use {0} to run unit tests."), [{l10n.t("Testing View")}])}
, imageUri: require("../resources/testing.png") }]; }, []); @@ -41,26 +47,26 @@ export default function TourPage() { const steps = useMemo(() => { const startingPage =
- logo -

Welcome to use Java Tools

-
lightweight, performant, powerful.
-
- + {l10n.t("logo")} +

{l10n.t("Welcome to use Java Tools")}

+
{l10n.t("lightweight, performant, powerful.")}
+
+
; const pages = contentPages.map(elem =>
-

{elem.title}

+

{elem.label}

{elem.description}
- {elem.title} - - + {elem.label} + +
); const endingPage =
- logo -

You're good to go!

-
Next, start using Java!
-
+ {l10n.t("logo")} +

{l10n.t("You're good to go!")}

+
{l10n.t("Next, start using Java!")}
+
; return [startingPage, ...pages, endingPage]; @@ -87,7 +93,7 @@ export default function TourPage() { }, [step, steps.length]); if (step >= steps.length) { - return
Loading...
; + return
{l10n.t("Loading...")}
; } return ( diff --git a/src/welcome/assets/index.ts b/src/welcome/assets/index.ts index 9a199a52..7c231b3e 100644 --- a/src/welcome/assets/index.ts +++ b/src/welcome/assets/index.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import "../../l10n/browser"; + import { createElement } from "react"; import { createRoot } from "react-dom/client"; import { GetStartedPage } from "./components/GetStartedPage"; diff --git a/src/welcome/index.ts b/src/welcome/index.ts index 92ef4ec6..40267a1a 100644 --- a/src/welcome/index.ts +++ b/src/welcome/index.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +import { escapeHtml, webviewLanguage, localizationBootstrap } from "../l10n/host"; import * as path from "path"; import * as vscode from "vscode"; import { instrumentSimpleOperation, sendInfo } from "vscode-extension-telemetry-wrapper"; @@ -40,7 +41,7 @@ export async function showWelcomeWebview(context: vscode.ExtensionContext, _oper welcomeView = vscode.window.createWebviewPanel( "java.welcome", - "Java Help Center", + vscode.l10n.t("Java Help Center"), column, { enableScripts: true, @@ -70,6 +71,7 @@ function onDidDisposeWebviewPanel() { } async function initializeWelcomeView(context: vscode.ExtensionContext, webviewPanel: vscode.WebviewPanel, onDisposeCallback: () => void) { + webviewPanel.title = vscode.l10n.t("Java Help Center"); webviewPanel.iconPath = { light: vscode.Uri.file(path.join(context.extensionPath, "caption.light.svg")), dark: vscode.Uri.file(path.join(context.extensionPath, "caption.dark.svg")) @@ -106,15 +108,16 @@ function getHtmlForWebview(webviewPanel: vscode.WebviewPanel, scriptPath: string const nonce = getNonce(); const cspSource = webviewPanel.webview.cspSource; return ` - + - Java Help Center + ${escapeHtml(vscode.l10n.t("Java Help Center"))} + ${localizationBootstrap(nonce)}
diff --git a/test-plans/java-webview-migration.yaml b/test-plans/java-webview-migration.yaml index 9cd663c4..255ed5ea 100644 --- a/test-plans/java-webview-migration.yaml +++ b/test-plans/java-webview-migration.yaml @@ -22,7 +22,6 @@ # 8. Overview — command "Java: Overview" (java.overview) # # Prerequisites: -# - vscode-java repo cloned as ../../vscode-java (provides the Maven sample project) # - JDK installed (Project Settings / Configure Runtime need a working LS) # # Usage: npx autotest run test-plans/java-webview-migration.yaml @@ -31,9 +30,10 @@ name: "Java Pack Webview Migration — UI Smoke (PR #1616)" description: | Open each webview migrated to React 19 + @vscode-elements/elements in PR #1616 and verify the headings, tab labels, and action buttons rendered in the PR's - screenshots are present in the actual webview text. A Maven sample project is - used so the Maven tab in Project Settings and the project list in Configure - Java Runtime become visible. + screenshots are present in the actual webview text. Also guards English source + fallback after localization. Native actions and restoration are covered by + localization/en-native.yaml in a separate run (AutoTest has 12 command slots). + Uses an existing lightweight Maven fixture; no sample repository is required. logging: enabled: true @@ -44,8 +44,11 @@ setup: extensions: - "vscjava.vscode-java-pack" vscodeVersion: "stable" - workspace: "../../vscode-java/test/resources/projects/maven/salut" + workspace: "../test-fixtures/super-implementation" timeout: 120 + settings: + java.help.showReleaseNotes: false + java.help.firstView: "none" # Pre-configure the formatter profile path so the Formatter Settings webview # bypasses the "No active Formatter Profile found" notification (which the # smoke-test driver suppresses, leaving the webview stuck). The profile XML @@ -58,7 +61,7 @@ steps: # Java Runtime, Configure Classpath) have project data to render. ────── - id: "ls-ready" action: "waitForLanguageServer" - verify: "Maven salut workspace has loaded; the Java extension and the pack webview commands are ready" + verify: "The Java workspace has loaded and the pack webview commands are ready" # waitForLanguageServer is authoritative — skip LLM screenshot re-check # (status bar may still show "Java: Searching... 0%" for background # indexing right after the LS reports ready). @@ -72,7 +75,9 @@ steps: # Extensions...". # ══════════════════════════════════════════════════════════════════════ - id: "open-help-center" - action: "run command Java: Help Center" + action: "executeVSCodeCommand java.welcome" + verifyEditorTab: + title: "Java Help Center" verify: "Java Help Center webview opens" waitBefore: 1 @@ -91,8 +96,13 @@ steps: - "Install Extensions" timeout: 30 + # Focus the workbench before dispatching a closing keybinding: destroying the + # focused webview during Playwright's keypress can leave the driver waiting. + - id: "focus-workbench-after-help-center" + action: "click side tab Explorer" + - id: "close-help-center" - action: "run command View: Close All Editors" + action: "executeVSCodeCommand workbench.action.closeAllEditors" # ══════════════════════════════════════════════════════════════════════ # 2. Tips for Beginners (java.gettingStarted) @@ -100,7 +110,9 @@ steps: # Code Editing / Debugging / FAQ. # ══════════════════════════════════════════════════════════════════════ - id: "open-beginner-tips" - action: "run command Java: Tips for Beginners" + action: "executeVSCodeCommand java.gettingStarted" + verifyEditorTab: + title: "Tips for Beginners" verify: "Tips for Beginners webview opens" waitBefore: 1 @@ -116,8 +128,11 @@ steps: - "FAQ" timeout: 30 + - id: "focus-workbench-after-beginner-tips" + action: "click side tab Explorer" + - id: "close-beginner-tips" - action: "run command View: Close All Editors" + action: "executeVSCodeCommand workbench.action.closeAllEditors" # ══════════════════════════════════════════════════════════════════════ # 3. Install New JDK (java.installJdk) @@ -125,7 +140,9 @@ steps: # "Others", "Reload Window" button. # ══════════════════════════════════════════════════════════════════════ - id: "open-install-jdk" - action: "run command Java: Install New JDK" + action: "executeVSCodeCommand java.installJdk" + verifyEditorTab: + title: "Install New JDK" verify: "Install JDK webview opens" waitBefore: 1 @@ -140,8 +157,11 @@ steps: - "Reload Window" timeout: 30 + - id: "focus-workbench-after-install-jdk" + action: "click side tab Explorer" + - id: "close-install-jdk" - action: "run command View: Close All Editors" + action: "executeVSCodeCommand workbench.action.closeAllEditors" # ══════════════════════════════════════════════════════════════════════ # 4. Configure Java Runtime (java.runtime) @@ -153,7 +173,9 @@ steps: # Classpath / JDK Runtime nav after the React 19 upgrade. # ══════════════════════════════════════════════════════════════════════ - id: "open-java-runtime" - action: "run command Java: Configure Java Runtime" + action: "executeVSCodeCommand java.runtime" + verifyEditorTab: + title: "Project Settings" # No `verify:` — transitional step. The next `verify-java-runtime` # step waits 3s and asserts the rendered Classpath / JDK Runtime nav. # On slower CI the screenshot taken at command-return can capture a @@ -188,8 +210,11 @@ steps: If the dropdown was already expanded before waiting, unchanged screenshots are expected and should pass, provided a runtime entry is still visible. + - id: "focus-workbench-after-java-runtime" + action: "click side tab Explorer" + - id: "close-java-runtime" - action: "run command View: Close All Editors" + action: "executeVSCodeCommand workbench.action.closeAllEditors" # ══════════════════════════════════════════════════════════════════════ # 5. Project Settings (java.projectSettings) @@ -197,7 +222,9 @@ steps: # the Classpath section's three tabs Sources / JDK Runtime / Libraries. # ══════════════════════════════════════════════════════════════════════ - id: "open-project-settings" - action: "run command Java: Open Project Settings" + action: "executeVSCodeCommand java.projectSettings" + verifyEditorTab: + title: "Project Settings" verify: "Project Settings webview opens" waitBefore: 1 @@ -215,8 +242,11 @@ steps: - "Libraries" timeout: 30 + - id: "focus-workbench-after-project-settings" + action: "click side tab Explorer" + - id: "close-project-settings" - action: "run command View: Close All Editors" + action: "executeVSCodeCommand workbench.action.closeAllEditors" # ══════════════════════════════════════════════════════════════════════ # 6. Configure Classpath (java.classpathConfiguration) @@ -225,7 +255,9 @@ steps: # Help Center screenshot. # ══════════════════════════════════════════════════════════════════════ - id: "open-classpath-config" - action: "run command Java: Configure Classpath" + action: "executeVSCodeCommand java.classpathConfiguration" + verifyEditorTab: + title: "Project Settings" # No `verify:` — transitional step. The next `verify-classpath-config` # step waits 3s and asserts Sources / JDK Runtime / Libraries. # Screenshot at command-return can be pre-render on slower CI. @@ -241,8 +273,46 @@ steps: - "Libraries" timeout: 30 + - id: "focus-workbench-after-classpath-config" + action: "click side tab Explorer" + - id: "close-classpath-config" - action: "run command View: Close All Editors" + action: "executeVSCodeCommand workbench.action.closeAllEditors" + + - id: "open-overview" + action: "executeVSCodeCommand java.overview" + verifyEditorTab: + title: "Java Overview" + verifyWebview: + contains: + - "Java Overview" + - "Start" + - "Extensions" + timeout: 30 + + - id: "focus-workbench-after-overview" + action: "click side tab Explorer" + + - id: "close-overview" + action: "executeVSCodeCommand workbench.action.closeAllEditors" + + - id: "open-extensions-guide" + action: "executeVSCodeCommand java.extGuide" + verifyEditorTab: + title: "Java Extensions Guide" + verifyWebview: + contains: + - "Basics" + - "Frameworks" + - "Install Selected" + - "Install All" + timeout: 30 + + - id: "focus-workbench-after-extensions-guide" + action: "click side tab Explorer" + + - id: "close-extensions-guide" + action: "executeVSCodeCommand workbench.action.closeAllEditors" # ══════════════════════════════════════════════════════════════════════ # 7. Formatter Settings (java.formatterSettings) @@ -273,10 +343,10 @@ steps: skipLlmVerify: true - id: "close-profile-file-before-formatter" - action: "run command View: Close All Editors" + action: "executeVSCodeCommand workbench.action.closeAllEditors" - id: "open-formatter-settings" - action: "run command Java: Open Java Formatter Settings with Preview" + action: "executeVSCodeCommand java.formatterSettings" # No `verify:` — transitional step. The next `verify-formatter-settings` # step waits 5s and asserts all six category labels via verifyWebview. # On slower CI the screenshot can capture the formatter XML file still @@ -300,28 +370,5 @@ steps: - "Wrapping" timeout: 45 - - id: "close-formatter-settings" - action: "run command View: Close All Editors" - - # ══════════════════════════════════════════════════════════════════════ - # 8. Overview (java.overview) - # Not migrated in this PR (still on jQuery/Bootstrap), but the PR's - # "Testing" section verified Overview continues to render. Smoke-check - # that the page still loads to catch any side-effect regression from - # the React 19 upgrade. - # ══════════════════════════════════════════════════════════════════════ - - id: "open-overview" - action: "run command Java: Overview" - verify: "Overview webview opens" - waitBefore: 1 - - - id: "verify-overview" - action: "wait 3 seconds" - verify: "Overview page still renders after the migration" - verifyWebview: - contains: - - "Overview" - timeout: 30 - - - id: "close-overview" - action: "run command View: Close All Editors" + # Keep the custom formatter last: AutoTest's synthetic command chords can be + # swallowed by its embedded editor. Runner cleanup closes the owned window. diff --git a/test-plans/localization/en-native.yaml b/test-plans/localization/en-native.yaml new file mode 100644 index 00000000..35d25b87 --- /dev/null +++ b/test-plans/localization/en-native.yaml @@ -0,0 +1,86 @@ +name: "Java Pack - English Walkthrough, Native Actions and Restoration" +description: | + Exercise the original walkthrough command route, native settings actions and + actual Help Center restoration separately from webview smoke coverage, staying + within AutoTest's 12 unique command-and-argument keybinding slots. + +setup: + extension: "redhat.java" + extensions: + - "vscjava.vscode-java-pack" + vscodeVersion: "stable" + workspace: "../../test-fixtures/super-implementation" + timeout: 120 + settings: + java.help.showReleaseNotes: false + java.help.firstView: "none" + +steps: + - id: "java-workspace-ready" + action: "waitForLanguageServer" + skipLlmVerify: true + timeout: 180 + + - id: "open-original-walkthrough" + action: 'executeVSCodeCommand workbench.action.openWalkthrough "vscjava.vscode-java-pack#javaWelcome"' + # VS Code owns this tab title; the pack's walkthrough heading is inside it. + verifyEditorTab: + title: "Welcome" + timeout: 30 + + - id: "enable-native-awt-development" + action: "executeVSCodeCommand java.toggleAwtDevelopment true" + + # VS Code suppresses toast rendering with --enable-smoke-test-driver. Assert + # the command's persisted effect here; real message UI remains a manual gate. + - id: "verify-native-awt-setting" + action: "wait 2 seconds" + verifyFile: + path: "~/.vscode/settings.json" + matches: '"java\.completion\.filteredTypes"\s*:\s*\[(?![^\]]*java\.awt\.\*)[^\]]*\]' + timeout: 20 + + - id: "restore-native-awt-setting" + action: "executeVSCodeCommand java.toggleAwtDevelopment false" + + - id: "verify-restored-native-awt-setting" + action: "wait 2 seconds" + verifyFile: + path: "~/.vscode/settings.json" + contains: '"java.awt.*"' + timeout: 20 + + - id: "invoke-walkthrough-jdk-action" + action: "executeVSCodeCommand java.installJdk.fromWalkthrough" + verifyEditorTab: + title: "Install New JDK" + verifyWebview: + contains: + - "Install New JDK" + - "Reload Window" + timeout: 30 + + - id: "open-help-center-before-reload" + action: "executeVSCodeCommand java.welcome" + verifyEditorTab: + title: "Java Help Center" + verifyWebview: + contains: "Get Started" + timeout: 30 + + - id: "focus-workbench-before-reload" + action: "click side tab Explorer" + + - id: "reload-help-center" + action: "executeVSCodeCommand workbench.action.reloadWindow" + timeout: 60 + + - id: "verify-restored-help-center" + action: "wait 3 seconds" + verifyEditorTab: + title: "Java Help Center" + verifyWebview: + contains: + - "Java Help Center" + - "Get Started" + timeout: 45 diff --git a/test-plans/localization/zh-cn.yaml b/test-plans/localization/zh-cn.yaml new file mode 100644 index 00000000..ee3c551b --- /dev/null +++ b/test-plans/localization/zh-cn.yaml @@ -0,0 +1,195 @@ +# Requires an actual zh-cn VS Code launch, not merely an installed language pack. +# AutoTest 0.7.35 does not forward locale arguments; see docs/localization.md. +# Notification assertions also need a launch without --enable-smoke-test-driver. +# Kept outside the top-level CI discovery glob until locale launch is supported. +name: "Java Pack - Simplified Chinese Localization" +description: | + Acceptance checks for the original walkthrough, current public webview routes, + native messages and reload/restoration in a real zh-cn VS Code session. + The legacy Java Runtime page has no current command route; its serializer, + bootstrap and display labels are covered by the Node localization tests. + Do not count this scenario as run when VS Code launches in English. + +setup: + extension: "redhat.java" + extensions: + - "vscjava.vscode-java-pack" + - "MS-CEINTL.vscode-language-pack-zh-hans" + vscodeVersion: "stable" + workspace: "../../test-fixtures/super-implementation" + timeout: 120 + settings: + java.help.showReleaseNotes: false + java.help.firstView: "none" + workspaceSettings: + java.format.settings.url: ".vscode/java-formatter.xml" + +steps: + - id: "java-workspace-ready" + action: "waitForLanguageServer" + skipLlmVerify: true + timeout: 180 + + - id: "verify-original-walkthrough" + action: 'executeVSCodeCommand workbench.action.openWalkthrough "vscjava.vscode-java-pack#javaWelcome"' + # VS Code owns this tab title, not the pack's walkthrough heading. + verifyEditorTab: + title: "欢迎" + timeout: 30 + + - id: "enable-native-awt-development" + action: "executeVSCodeCommand java.toggleAwtDevelopment true" + + - id: "verify-translated-native-action" + action: "wait 2 seconds" + verifyNotification: "已启用 Java AWT 开发。" + timeout: 20 + + - id: "restore-native-action-setting" + action: "executeVSCodeCommand java.toggleAwtDevelopment false" + + - id: "verify-restored-native-action-message" + action: "wait 2 seconds" + verifyNotification: "已禁用 Java AWT 开发。" + timeout: 20 + + - id: "open-walkthrough-jdk-action" + action: "executeVSCodeCommand java.installJdk.fromWalkthrough" + verifyEditorTab: + title: "安装新 JDK" + verifyWebview: + contains: + - "安装新 JDK" + - "重新加载窗口" + - "其他" + notContains: "Reload Window" + timeout: 30 + + - id: "verify-help-center" + action: "executeVSCodeCommand java.welcome" + verifyEditorTab: + title: "Java 帮助中心" + verifyWebview: + contains: + - "Java 帮助中心" + - "开始使用" + - "配置 Java 运行时" + - "文档" + notContains: "Get Started" + timeout: 30 + + - id: "verify-beginner-tips" + action: "executeVSCodeCommand java.gettingStarted" + verifyEditorTab: + title: "新手提示" + verifyWebview: + contains: + - "新手提示" + - "快速入门" + - "代码编辑" + - "常见问题" + - "设置工作区" + - "System.out.println" + timeout: 30 + + - id: "verify-extensions-guide" + action: "executeVSCodeCommand java.extGuide" + verifyEditorTab: + title: "Java 扩展指南" + verifyWebview: + contains: + - "基础" + - "框架" + - "安装所选扩展" + - "安装全部扩展" + - "Language Support for Java by Red Hat" + timeout: 30 + + - id: "verify-overview" + action: "executeVSCodeCommand java.overview" + verifyEditorTab: + title: "Java 概述" + verifyWebview: + contains: + - "Java 概述" + - "开始" + - "扩展" + - "配置" + timeout: 30 + + - id: "verify-runtime-command-route" + action: "executeVSCodeCommand java.runtime" + verifyEditorTab: + title: "项目设置" + verifyWebview: + contains: + - "类路径" + - "JDK 运行时" + - "刷新 JDK" + - "查找本地 JDK" + timeout: 30 + + - id: "verify-project-settings" + action: "executeVSCodeCommand java.projectSettings" + verifyEditorTab: + title: "项目设置" + verifyWebview: + contains: + - "类路径" + - "编译器" + - "格式化程序" + - "源代码" + - "库" + timeout: 30 + + - id: "focus-help-center-before-reload" + action: "executeVSCodeCommand java.welcome" + verifyWebview: + contains: "Java 帮助中心" + timeout: 30 + + - id: "focus-workbench-before-reload" + action: "click side tab 资源管理器" + + - id: "reload-window" + action: "executeVSCodeCommand workbench.action.reloadWindow" + timeout: 60 + + - id: "verify-restored-translated-title-and-content" + action: "wait 3 seconds" + verifyEditorTab: + title: "Java 帮助中心" + verifyWebview: + contains: + - "Java 帮助中心" + - "开始使用" + notContains: "Get Started" + timeout: 45 + + - id: "create-formatter-profile" + action: | + insertLineInFile .vscode/java-formatter.xml 1 + + + + + + verifyFile: + path: "~/.vscode/java-formatter.xml" + contains: 'id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"' + skipLlmVerify: true + + - id: "verify-formatter-settings" + action: "executeVSCodeCommand java.formatterSettings" + verifyEditorTab: + title: "java-formatter.xml" + verifyWebview: + contains: + - "Java 格式化程序设置" + - "缩进" + - "空行" + - "注释" + - "换行" + - "缩进策略" + - "制表符" + timeout: 45 diff --git a/tests/helpers/l10n.js b/tests/helpers/l10n.js new file mode 100644 index 00000000..abbd2deb --- /dev/null +++ b/tests/helpers/l10n.js @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +function createL10n(bundle = {}) { + return { + bundle, + t: (message, ...args) => { + const values = args.length === 1 && typeof args[0] === "object" ? args[0] : args; + return (bundle[message] ?? message).replace(/\{(\w+)\}/g, (match, key) => values[key] === undefined ? match : String(values[key])); + }, + }; +} + +module.exports = { createL10n }; diff --git a/tests/java-runtime.test.js b/tests/java-runtime.test.js index 995060d6..b2a51078 100644 --- a/tests/java-runtime.test.js +++ b/tests/java-runtime.test.js @@ -32,7 +32,7 @@ function setupComponents() { let html; const globals = { acquireVsCodeApi: () => ({ postMessage: message => messages.push(message) }), - document: { getElementById: () => ({}) }, + document: { getElementById: id => id === "java-pack-l10n" ? null : ({}) }, window: { addEventListener: (_, listener) => { receive = listener; } }, }; const mocks = { @@ -88,6 +88,7 @@ function setup(version = "1.57.0") { onDidDispose: () => ({ dispose() {} }), }; const vscode = { + l10n: require("./helpers/l10n").createL10n(), extensions: { getExtension: id => id === "redhat.java" ? extension : id === "vscjava.vscode-java-dependency" ? projectManager : undefined, @@ -111,7 +112,10 @@ function setup(version = "1.57.0") { }, commands: { executeCommand: async () => [] }, }; - const mocks = { vscode, "jdk-utils": jdkUtils, "expand-home-dir": home => home }; + const mocks = { + vscode, "jdk-utils": jdkUtils, "expand-home-dir": home => home, + "../l10n/host": { escapeHtml: text => text, webviewLanguage: () => "en", localizationBootstrap: () => "" }, + }; const api = loadSource(path.join("src", "java-runtime", "utils", "upstreamApi.ts"), mocks, warnings); const webviewUtils = loadSource(path.join("src", "utils", "webview.ts"), {}, warnings); const jdt = loadSource(path.join("src", "utils", "jdt.ts"), { diff --git a/tests/localization.test.js b/tests/localization.test.js new file mode 100644 index 00000000..3a8fcd00 --- /dev/null +++ b/tests/localization.test.js @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); +const os = require("node:os"); +const test = require("node:test"); +const { checkCatalog, checkManifest, checkRuntime, checkExtraction, invariantTokens, manifestText } = require("../scripts/check-localization"); + +test("every manifest UI field resolves and all discovered locale catalogs are complete", () => { + const { source } = checkManifest(); + assert.equal(Object.keys(source).length, 45); +}); + +test("runtime catalogs cover every shipped locale and exactly match extraction", () => { + checkRuntime(); + checkExtraction(); +}); + +test("placeholder guards allow reordering but reject missing, repeated or renamed parameters", () => { + const source = { message: "{first}: {second}" }; + checkCatalog(source, { message: "{second}: {first}" }, "reordered"); + for (const message of ["{first}", "{first} {first}", "{first} {different}"]) { + assert.throws(() => checkCatalog(source, { message }, "synthetic")); + } +}); + +test("catalog guards reject missing, extra, empty, changed-link and changed-icon translations", () => { + const source = { message: "$(info) __[Open](command:open?%22value%22)__" }; + for (const candidate of [ + {}, { ...source, extra: "extra" }, { message: " " }, + { message: "$(info) __[Open](command:different)__" }, + { message: "$(warning) __[Open](command:open?%22value%22)__" }, + { message: "$(info) [Open](command:open?%22value%22)" }, + ]) { + assert.throws(() => checkCatalog(source, candidate, "synthetic")); + } + assert.throws(() => checkCatalog({ message: "Ready 👍" }, { message: "Ready 🔄" }, "synthetic")); +}); + +test("runtime guards discover added locales and reject missing catalogs and keys", () => { + const directory = fs.mkdtempSync(path.join(os.tmpdir(), "java-pack-catalog-test-")); + try { + fs.mkdirSync(path.join(directory, "l10n")); + fs.writeFileSync(path.join(directory, "package.nls.zz.json"), "{}"); + fs.writeFileSync(path.join(directory, "l10n", "bundle.l10n.json"), '{"Hello":"Hello"}'); + assert.throws(() => checkRuntime(directory), /shipped locales differ/); + const translated = path.join(directory, "l10n", "bundle.l10n.zz.json"); + fs.writeFileSync(translated, "{}"); + assert.throws(() => checkRuntime(directory), /catalog keys differ/); + fs.writeFileSync(translated, '{"Hello":"Test"}'); + checkRuntime(directory); + } finally { + fs.rmSync(directory, { recursive: true, force: true }); + } +}); + +test("extraction checking rejects drift without modifying committed resources", () => { + const directory = fs.mkdtempSync(path.join(os.tmpdir(), "java-pack-extraction-test-")); + try { + fs.mkdirSync(path.join(directory, "src")); + fs.mkdirSync(path.join(directory, "l10n")); + fs.writeFileSync(path.join(directory, "src", "test.ts"), 'import * as l10n from "@vscode/l10n"; l10n.t("New message");'); + const catalog = path.join(directory, "l10n", "bundle.l10n.json"); + fs.writeFileSync(catalog, "{}"); + assert.throws(() => checkExtraction(directory), /extraction drift/); + assert.equal(fs.readFileSync(catalog, "utf8"), "{}"); + } finally { + fs.rmSync(directory, { recursive: true, force: true }); + } +}); + +test("manifest translation preserves every action target and codicon", () => { + const { source, manifest } = checkManifest(); + const chinese = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.nls.zh-cn.json"), "utf8")); + const resolve = (text, catalog) => catalog[text.slice(1, -1)] ?? source[text.slice(1, -1)]; + for (const reference of manifestText(manifest)) { + const english = resolve(reference, {}); + assert.equal(resolve(reference, {}), english, "Unsupported locale uses the English default"); + assert.deepEqual(invariantTokens(resolve(reference, chinese)), invariantTokens(english)); + } + const missing = { ...chinese }; + delete missing["commands.overview.title"]; + assert.equal(resolve("%commands.overview.title%", missing), "Overview"); + assert.notEqual(resolve("%commands.overview.title%", chinese), "Overview"); +}); diff --git a/tests/localized-actions.test.js b/tests/localized-actions.test.js new file mode 100644 index 00000000..6439fbdb --- /dev/null +++ b/tests/localized-actions.test.js @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); +const test = require("node:test"); +const vm = require("node:vm"); +const ts = require("typescript"); +const { createL10n } = require("./helpers/l10n"); +const chinese = require("../l10n/bundle.l10n.zh-cn.json"); + +function loadSource(relativePath, mocks) { + const filename = path.join(__dirname, "..", relativePath); + const { outputText } = ts.transpileModule(fs.readFileSync(filename, "utf8"), { + compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020, esModuleInterop: true }, + fileName: filename, + }); + const module = { exports: {} }; + vm.runInNewContext(outputText, { + module, exports: module.exports, console, + require: name => Object.hasOwn(mocks, name) ? mocks[name] : require(name), + }, { filename }); + return module.exports; +} + +function formatter(url, exists = true) { + const calls = []; + const dialogs = []; + let choose; + const vscode = { + l10n: createL10n(chinese), + languages: { createDiagnosticCollection: () => ({ set() {} }) }, + workspace: { + getConfiguration: () => ({ get: key => key === "format.settings.url" ? url : undefined }), + onDidChangeConfiguration() {}, onDidChangeTextDocument() {}, + }, + commands: { executeCommand: command => calls.push(command) }, + window: { + showInformationMessage: async (message, ...actions) => { + dialogs.push({ message, actions }); + return choose === undefined ? undefined : actions[choose]; + }, + }, + }; + vscode.window.showErrorMessage = vscode.window.showInformationMessage; + const utils = { + isRemote: value => value.startsWith("https:"), + getProfilePath: async () => "profile.xml", + addDefaultProfile: () => calls.push("default"), + openFormatterSettings: () => calls.push("settings"), + downloadFile: async () => "", + parseProfile: () => ({ isValid: false }), + }; + const { JavaFormatterSettingsEditorProvider } = loadSource(path.join("src", "formatter-settings", "index.ts"), { + vscode, "fs-extra": { pathExists: async () => exists }, + "../utils": { getNonce: () => "test" }, + "../l10n/host": {}, + "./utils": utils, + "./FormatterConstants": { JavaConstants: { SETTINGS_URL_KEY: "format.settings.url" }, VSCodeSettings: {}, SupportedSettings: {} }, + "./FormatterConverter": {}, + "./types": { ExampleKind: { INDENTATION_EXAMPLE: "Indentation" } }, + "./RemoteProfileProvider": { remoteProfileProvider: { setContent: () => calls.push("remote-content") } }, + "vscode-extension-telemetry-wrapper": { + instrumentOperation: (name, action) => (...args) => action(name, ...args), + sendInfo() {}, sendError() {}, setUserError() {}, + }, + }); + const provider = new JavaFormatterSettingsEditorProvider({}); + provider.downloadAndUse = async () => { calls.push("download"); return true; }; + return { provider, calls, dialogs, select: index => { choose = index; } }; +} + +test("translated formatter Yes routes to create while No and cancellation do nothing", async () => { + for (const selection of [0, 1, undefined]) { + const s = formatter(undefined); + s.select(selection); + await s.provider.checkProfileSettings(); + assert.equal(s.dialogs[0].actions[0].title, chinese.Yes); + assert.equal(s.calls.includes("default"), selection === 0); + } +}); + +test("translated formatter remote actions preserve read-only/download routing and cancellation", async () => { + for (const selection of [0, 1, undefined]) { + const s = formatter("https://example.test/profile.xml"); + s.select(selection); + const checked = await s.provider.checkProfileSettings(); + assert.equal(checked, selection === 0); + assert.equal(s.calls.includes("remote-content"), selection === 0); + assert.equal(s.calls.includes("download"), selection === 1); + assert.equal(s.provider.readOnly, selection === 0); + } +}); + +test("translated missing-profile settings/default actions remain distinct", async () => { + for (const selection of [0, 1, undefined]) { + const s = formatter("profile.xml", false); + s.select(selection); + await s.provider.checkProfileSettings(); + assert.equal(s.calls.includes("settings"), selection === 0); + assert.equal(s.calls.includes("default"), selection === 1); + } +}); + +test("translated reload and invalid-profile actions preserve identity and cancellation", async () => { + for (const selection of [0, 1, undefined]) { + const s = formatter(undefined); + s.provider.webviewPanel = { visible: true }; + s.select(selection); + s.provider.onChangeProfileSettings(); + await Promise.resolve(); + assert.equal(s.calls.includes("workbench.action.webview.reloadWebviewAction"), selection === 0); + await s.provider.parseProfileAndUpdate({}); + await Promise.resolve(); + assert.equal(s.calls.includes("settings"), selection === 0); + } +}); + +test("translated recommendation Install action routes independently of its caption", async () => { + const calls = []; + let choose = true; + const { recommendExtension } = loadSource(path.join("src", "utils", "index.ts"), { + vscode: { + l10n: createL10n(chinese), + window: { showInformationMessage: async (_, action) => { + assert.equal(action.title, chinese.Install); + return choose ? action : undefined; + } }, + commands: { executeCommand: (...args) => calls.push(args) }, + }, + "./idle": {}, "./scheduler": {}, "./release-notes": {}, "./extension": {}, + "vscode-extension-telemetry-wrapper": {}, + }); + await recommendExtension("example.extension", "message"); + choose = false; + await recommendExtension("example.extension", "message"); + assert.deepEqual(calls, [["java.helper.installExtension", "example.extension", "example.extension"]]); +}); + +test("native message mock preserves upstream details and supports reordered placeholders", () => { + const l10n = createL10n(chinese); + assert.equal(l10n.t('"{0}" is not supported in id: "{1}".', "raw-value", "raw.id"), 'ID“raw.id”不支持“raw-value”。'); + assert.equal(l10n.t("Missing {0}", "detail"), "Missing detail"); +}); diff --git a/tests/project-settings.test.js b/tests/project-settings.test.js index 2d1ee2af..fabb73c7 100644 --- a/tests/project-settings.test.js +++ b/tests/project-settings.test.js @@ -37,6 +37,7 @@ function setupHandler() { let installs = [jdk21]; const uri = value => ({ fsPath: fileURLToPath(value), toString: () => value }); const vscode = { + l10n: require("./helpers/l10n").createL10n(), Uri: { parse: uri }, workspace: { onDidChangeConfiguration: () => ({ dispose() {} }) }, window: { showErrorMessage: async message => { notifications.push(message); } }, @@ -229,6 +230,7 @@ function renderJdk(installs, activePath) { "react-redux": { useSelector: selector => selector(state), useDispatch: () => () => {} }, "../../../vscode/utils": { ClasspathRequest: {}, CommonRequest: {} }, "../classpathConfigurationViewSlice": {}, + "../../../../../l10n/richText": loadSource(path.join("src", "l10n", "richText.tsx")), }); return renderToStaticMarkup(createElement(JdkRuntime)); } diff --git a/tests/webview-localization.test.js b/tests/webview-localization.test.js new file mode 100644 index 00000000..336ff993 --- /dev/null +++ b/tests/webview-localization.test.js @@ -0,0 +1,211 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); +const test = require("node:test"); +const vm = require("node:vm"); +const ts = require("typescript"); +const l10n = require("@vscode/l10n"); +const { createL10n } = require("./helpers/l10n"); + +function loader(mocks = {}, globals = {}) { + const cache = new Map(); + function load(relativePath) { + const filename = path.resolve(__dirname, "..", relativePath); + if (cache.has(filename)) return cache.get(filename).exports; + const module = { exports: {} }; + cache.set(filename, module); + const { outputText } = ts.transpileModule(fs.readFileSync(filename, "utf8"), { + compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020, esModuleInterop: true, jsx: ts.JsxEmit.ReactJSX }, + fileName: filename, + }); + const resolve = name => { + if (Object.hasOwn(mocks, name)) return mocks[name]; + if (!name.startsWith(".")) return require(name); + const absolute = path.resolve(path.dirname(filename), name); + const candidate = [absolute + ".ts", absolute + ".tsx", path.join(absolute, "index.ts")].find(fs.existsSync); + assert.ok(candidate, `Unresolved test module ${name} in ${filename}`); + return load(candidate); + }; + vm.runInNewContext(outputText, { module, exports: module.exports, require: resolve, console, process, Buffer, ...globals }, { filename }); + return module.exports; + } + return load; +} + +test.afterEach(() => l10n.config({ contents: {} })); + +test("native bootstrap keeps hostile catalog text inert and escapes HTML attributes", () => { + const malicious = '&\'\u2028\u2029'; + const bundle = { message: malicious }; + const load = loader({ vscode: { env: { language: 'zh-cn" data-bad="true' }, l10n: { bundle } } }); + const host = load(path.join("src", "l10n", "host.ts")); + const script = host.localizationBootstrap('nonce"&'); + assert.equal((script.match(/<\/script>/g) || []).length, 1); + assert.ok(!script.includes("") + 1, script.lastIndexOf("")); + assert.equal(JSON.parse(serialized).bundle.message, malicious); + assert.equal(host.webviewLanguage(), "zh-cn" data-bad="true"); + assert.equal(host.formatHtml("{0} & {1}", ["link", "text"]), + "<b>link</b> & text"); + assert.throws(() => host.formatHtml("{2}", []), /Unknown localized HTML placeholder/); +}); + +test("browser config uses only the host bundle and falls back for missing bundle/key", () => { + const document = { documentElement: {}, getElementById: () => ({ textContent: JSON.stringify({ + language: "zh-cn", bundle: { "Hello {name}": "{name},你好" }, + }) }) }; + loader({}, { document })(path.join("src", "l10n", "browser.ts")); + assert.equal(document.documentElement.lang, "zh-cn"); + assert.equal(l10n.t("Hello {name}", { name: "Java" }), "Java,你好"); + assert.equal(l10n.t("Missing {0}", "key"), "Missing key"); + loader({}, { document: { getElementById: () => null } })(path.join("src", "l10n", "browser.ts")); + assert.equal(l10n.t("Hello {name}", { name: "Java" }), "Hello Java"); +}); + +test("malformed bootstraps fail explicitly instead of pretending localization succeeded", () => { + for (const textContent of ["not JSON", "null", '{"language":"zh-cn","bundle":[]}', '{"language":"zh-cn","bundle":{"x":42}}']) { + assert.throws(() => loader({}, { document: { + getElementById: () => ({ textContent }), documentElement: {}, + } })(path.join("src", "l10n", "browser.ts"))); + } +}); + +test("reordered rich text retains trusted links and escapes translated markup", () => { + const { createElement } = require("react"); + const { renderToStaticMarkup } = require("react-dom/server"); + const { richText } = loader()(path.join("src", "l10n", "richText.tsx")); + l10n.config({ contents: { "Use {0} then {1}.": "{1} {0}" } }); + const html = renderToStaticMarkup(createElement("p", null, richText(l10n.t("Use {0} then {1}."), [ + createElement("a", { href: "command:stable" }, "Java"), "JDK", + ]))); + assert.equal(html, '

JDK <script>bad</script> Java

'); + assert.throws(() => richText("{2}", []), /Unknown localized React placeholder/); +}); + +test("display mappings are lazy and leave formatter protocol, candidates, defaults and XML values unchanged", () => { + const load = loader(); + const constants = load(path.join("src", "formatter-settings", "FormatterConstants.ts")); + const { ExampleKind } = load(path.join("src", "formatter-settings", "types.ts")); + const { FormatterConverter } = load(path.join("src", "formatter-settings", "FormatterConverter.ts")); + const labels = load(path.join("src", "formatter-settings", "assets", "labels.ts")); + const { ProjectType } = load(path.join("src", "utils", "webview.ts")); + const { projectTypeLabel } = load(path.join("src", "l10n", "display.ts")); + const chinese = require("../l10n/bundle.l10n.zh-cn.json"); + const settings = new Map(constants.getSupportedVSCodeSettings()); + for (let version = 1; version <= 23; version++) { + for (const [id, setting] of constants.getSupportedProfileSettings(version)) settings.set(id, setting); + } + const snapshot = JSON.stringify([...settings]); + for (const setting of settings.values()) assert.equal(labels.formatterSettingLabel(setting), setting.name); + assert.equal(projectTypeLabel(ProjectType.UnmanagedFolder), "Unmanaged folder"); + l10n.config({ contents: chinese }); + for (const setting of settings.values()) { + assert.ok(Object.hasOwn(chinese, setting.name), `Unmapped formatter label: ${setting.name}`); + assert.equal(labels.formatterSettingLabel(setting), chinese[setting.name]); + for (const candidate of setting.candidates || []) { + assert.equal(labels.formatterCandidateLabel(candidate), chinese[candidate] ?? candidate); + } + } + assert.equal(JSON.stringify([...settings]), snapshot); + assert.deepEqual(Object.values(ProjectType), ["Default project", "Unmanaged folder", "Maven", "Gradle", "Others"]); + assert.equal(projectTypeLabel(ProjectType.UnmanagedFolder), "非托管文件夹"); + assert.equal(projectTypeLabel(ProjectType.Maven), "Maven"); + assert.deepEqual(Object.values(ExampleKind), ["Indentation", "Blank line", "Comment", "Insert Line", "Braced type", + "Braced record", "Braced enum", "Annotation and anonymous", "Whitespace", "Wrapping"]); + for (const kind of Object.values(ExampleKind)) assert.equal(labels.formatterExampleLabel(kind), chinese[kind]); + const { TABULATION_CHAR, KEEP_TYPE_DECLARATION_ON_ONE_LINE } = constants.SupportedSettings; + assert.equal(constants.getDefaultValue(TABULATION_CHAR), "tab"); + assert.equal(FormatterConverter.webView2ProfileConvert(TABULATION_CHAR, "tab"), "tab"); + for (const [candidate, xml] of [["never", "one_line_never"], ["if empty", "one_line_if_empty"], + ["if at most one item", "one_line_if_single_item"]]) { + assert.equal(FormatterConverter.webView2ProfileConvert(KEEP_TYPE_DECLARATION_ON_ONE_LINE, candidate), xml); + assert.equal(FormatterConverter.profile2WebViewConvert(KEEP_TYPE_DECLARATION_ON_ONE_LINE, xml), candidate); + } +}); + +test("translated Help Center actions retain the exact command URIs and telemetry identities", () => { + const { createElement } = require("react"); + const { renderToStaticMarkup } = require("react-dom/server"); + const load = loader({ "../utils": { WEBVIEW_ID: "java.welcome" } }, { navigator: { platform: "win32", userAgent: "Windows" } }); + const { default: QuickActionPanel } = load(path.join("src", "welcome", "assets", "components", "QuickActionPanel.tsx")); + const { default: SocialMediaPanel } = load(path.join("src", "welcome", "assets", "components", "SocialMediaPanel.tsx")); + const render = () => renderToStaticMarkup(createElement("div", null, createElement(QuickActionPanel), createElement(SocialMediaPanel))); + const english = render(); + l10n.config({ contents: require("../l10n/bundle.l10n.zh-cn.json") }); + const chinese = render(); + const hrefs = html => [...html.matchAll(/href="([^"]+)"/g)].map(match => match[1]); + assert.deepEqual(hrefs(chinese), hrefs(english)); + assert.match(chinese, /创建/); + assert.match(chinese, /文档/); + assert.doesNotMatch(chinese, />Documentation disposable, + webview: { cspSource: "test-source", asWebviewUri: () => "https://webview.test/script.js", + onDidReceiveMessage: () => disposable, postMessage: () => true }, + }; + const context = { extensionPath: "test-extension", asAbsolutePath: value => value, subscriptions: [], + globalState: { get() {}, update() {} } }; + const vscode = { + l10n: createL10n(bundle), env: { language: "zh-cn" }, ViewColumn: { One: 1, Active: 1 }, + Uri: { file: fsPath => ({ fsPath }) }, + extensions: { all: [], getExtension() {}, onDidChange: () => disposable }, + workspace: { getConfiguration: () => ({ get() {} }), onDidChangeConfiguration: () => disposable, onDidChangeTextDocument: () => disposable }, + languages: { createDiagnosticCollection: () => ({ set() {} }) }, + window: { createWebviewPanel: () => panel, showErrorMessage: async () => undefined }, + }; + const mockHandler = class { dispose() {} }; + const mocks = { + vscode, + "../utils": { getExtensionContext: () => context, getNonce: () => "stable-nonce" }, + "./handlers/ClasspathRequestHandler": { ClasspathRequestHandler: mockHandler }, + "./handlers/CompilerRequestHandler": { CompilerRequestHandler: mockHandler }, + "./handlers/MavenRequestHandler": { MavenRequestHandler: mockHandler }, + "vscode-extension-telemetry-wrapper": { + instrumentOperation: (_, callback) => (...args) => callback("test", ...args), + instrumentSimpleOperation: (_, callback) => callback, sendInfo() {}, sendError() {}, setUserError() {}, + }, + }; + return { panel, context, mocks }; +} + +for (const [page, serializer, title] of [ + ["overview", "OverviewViewSerializer", "Java 概述"], + ["ext-guide", "JavaExtGuideViewSerializer", "Java 扩展指南"], + ["welcome", "WelcomeViewSerializer", "Java 帮助中心"], + ["beginner-tips", "BeginnerTipsViewSerializer", "新手提示"], + ["install-jdk", "InstallJdkViewSerializer", "安装新 JDK"], + ["java-runtime", "JavaRuntimeViewSerializer", "配置 Java 运行时"], + ["project-settings", "ProjectSettingsViewSerializer", "项目设置"], +]) { + test(`${serializer} rebuilds its title and bootstrap in the current display language`, async () => { + const s = hostEnvironment(); + const source = loader(s.mocks)(path.join("src", page, page === "project-settings" ? "projectSettingsView.ts" : "index.ts")); + await new source[serializer](s.context).deserializeWebviewPanel(s.panel, {}); + assert.equal(s.panel.title, title); + assert.match(s.panel.webview.html, //); + assert.ok(s.panel.webview.html.includes(`${title}`)); + assert.match(s.panel.webview.html, /id="java-pack-l10n"/); + assert.ok(s.panel.webview.html.indexOf('id="java-pack-l10n"') < s.panel.webview.html.indexOf('type="module"')); + assert.match(s.panel.webview.html, /script-src 'nonce-stable-nonce'/); + }); +} + +test("custom formatter editor rebuilds localized document HTML without changing its filename tab", async () => { + const s = hostEnvironment(); + const { JavaFormatterSettingsEditorProvider } = loader(s.mocks)(path.join("src", "formatter-settings", "index.ts")); + const provider = new JavaFormatterSettingsEditorProvider(s.context); + s.panel.title = "profile.xml"; + await provider.resolveCustomTextEditor({}, s.panel, {}); + assert.equal(s.panel.title, "profile.xml"); + assert.match(s.panel.webview.html, /Java 格式化程序设置<\/title>/); + assert.match(s.panel.webview.html, /id="java-pack-l10n"/); +});