[Awake]Add localization (#29751)

* [Awake] First steps for localization.

* Localizing all strings.

* Fix Spell Checker

* Spell checker

* Minor fixes, adding comments to resource strings.

* Cleaning up project file.

* adding resource comments
This commit is contained in:
Laszlo Nemeth 2023-11-20 19:40:54 +01:00 committed by GitHub
parent 42564e6c10
commit 106f90dc01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 364 additions and 12 deletions

View File

@ -79,6 +79,11 @@
<Compile Update="Program.cs">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Compile>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
@ -87,11 +92,17 @@
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Update="Microsoft.CodeAnalysis.NetAnalyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@ -6,12 +6,14 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reactive.Linq;
using System.Text;
using System.Threading;
using Awake.Core.Models;
using Awake.Core.Native;
using Awake.Properties;
using ManagedCommon;
using Microsoft.PowerToys.Telemetry;
using Microsoft.Win32;
@ -274,9 +276,9 @@ namespace Awake.Core
{
Dictionary<string, int> optionsList = new Dictionary<string, int>
{
{ "30 minutes", 1800 },
{ "1 hour", 3600 },
{ "2 hours", 7200 },
{ string.Format(CultureInfo.InvariantCulture, Resources.AWAKE_MINUTES, 30), 1800 },
{ Resources.AWAKE_1_HOUR, 3600 },
{ string.Format(CultureInfo.InvariantCulture, Resources.AWAKE_HOURS, 2), 7200 },
};
return optionsList;
}

View File

@ -6,11 +6,13 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Awake.Core.Models;
using Awake.Core.Native;
using Awake.Properties;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
@ -115,11 +117,11 @@ namespace Awake.Core
if (!startedFromPowerToys)
{
// If Awake is started from PowerToys, the correct way to exit it is disabling it from Settings.
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING, (uint)TrayCommands.TC_EXIT, "Exit");
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING, (uint)TrayCommands.TC_EXIT, Resources.AWAKE_EXIT);
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_SEPARATOR, 0, string.Empty);
}
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (keepDisplayOn ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED) | (mode == AwakeMode.PASSIVE ? Native.Constants.MF_DISABLED : Native.Constants.MF_ENABLED), (uint)TrayCommands.TC_DISPLAY_SETTING, "Keep screen on");
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (keepDisplayOn ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED) | (mode == AwakeMode.PASSIVE ? Native.Constants.MF_DISABLED : Native.Constants.MF_ENABLED), (uint)TrayCommands.TC_DISPLAY_SETTING, Resources.AWAKE_KEEP_SCREEN_ON);
}
// In case there are no tray shortcuts defined for the application default to a
@ -137,10 +139,10 @@ namespace Awake.Core
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_SEPARATOR, 0, string.Empty);
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (mode == AwakeMode.PASSIVE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_PASSIVE, "Off (keep using the selected power plan)");
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (mode == AwakeMode.INDEFINITE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_INDEFINITE, "Keep awake indefinitely");
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_POPUP | (mode == AwakeMode.TIMED ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)awakeTimeMenu, "Keep awake on interval");
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | Native.Constants.MF_DISABLED | (mode == AwakeMode.EXPIRABLE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_EXPIRABLE, "Keep awake until expiration date and time");
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (mode == AwakeMode.PASSIVE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_PASSIVE, Resources.AWAKE_OFF);
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (mode == AwakeMode.INDEFINITE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_INDEFINITE, Resources.AWAKE_KEEP_INDEFINITELY);
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_POPUP | (mode == AwakeMode.TIMED ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)awakeTimeMenu, Resources.AWAKE_KEEP_ON_INTERVAL);
Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | Native.Constants.MF_DISABLED | (mode == AwakeMode.EXPIRABLE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_EXPIRABLE, Resources.AWAKE_KEEP_UNTIL_EXPIRATION);
TrayIcon.Text = text;
}
@ -157,7 +159,7 @@ namespace Awake.Core
public override AccessibleRole Role => AccessibleRole.CheckButton;
public override string Name => _menuItem.Text + ", " + Role + ", " + (_menuItem.Checked ? "Checked" : "Unchecked");
public override string Name => _menuItem.Text + ", " + Role + ", " + (_menuItem.Checked ? Resources.AWAKE_CHECKED : Resources.AWAKE_UNCHECKED);
}
private sealed class CheckButtonToolStripMenuItem : ToolStripMenuItem

View File

@ -0,0 +1,171 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Awake.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Awake.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to 1 hour.
/// </summary>
internal static string AWAKE_1_HOUR {
get {
return ResourceManager.GetString("AWAKE_1_HOUR", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 1 minute.
/// </summary>
internal static string AWAKE_1_MINUTE {
get {
return ResourceManager.GetString("AWAKE_1_MINUTE", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Checked.
/// </summary>
internal static string AWAKE_CHECKED {
get {
return ResourceManager.GetString("AWAKE_CHECKED", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Exit.
/// </summary>
internal static string AWAKE_EXIT {
get {
return ResourceManager.GetString("AWAKE_EXIT", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} hours.
/// </summary>
internal static string AWAKE_HOURS {
get {
return ResourceManager.GetString("AWAKE_HOURS", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep awake indefinitely.
/// </summary>
internal static string AWAKE_KEEP_INDEFINITELY {
get {
return ResourceManager.GetString("AWAKE_KEEP_INDEFINITELY", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep awake on interval.
/// </summary>
internal static string AWAKE_KEEP_ON_INTERVAL {
get {
return ResourceManager.GetString("AWAKE_KEEP_ON_INTERVAL", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep screen on.
/// </summary>
internal static string AWAKE_KEEP_SCREEN_ON {
get {
return ResourceManager.GetString("AWAKE_KEEP_SCREEN_ON", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Keep awake until expiration date and time.
/// </summary>
internal static string AWAKE_KEEP_UNTIL_EXPIRATION {
get {
return ResourceManager.GetString("AWAKE_KEEP_UNTIL_EXPIRATION", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} minutes.
/// </summary>
internal static string AWAKE_MINUTES {
get {
return ResourceManager.GetString("AWAKE_MINUTES", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Off (keep using the selected power plan).
/// </summary>
internal static string AWAKE_OFF {
get {
return ResourceManager.GetString("AWAKE_OFF", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unchecked.
/// </summary>
internal static string AWAKE_UNCHECKED {
get {
return ResourceManager.GetString("AWAKE_UNCHECKED", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AWAKE_CHECKED" xml:space="preserve">
<value>Checked</value>
</data>
<data name="AWAKE_EXIT" xml:space="preserve">
<value>Exit</value>
</data>
<data name="AWAKE_1_HOUR" xml:space="preserve">
<value>1 hour</value>
</data>
<data name="AWAKE_HOURS" xml:space="preserve">
<value>{0} hours</value>
<comment>{0} shouldn't be removed. It will be replaced by a number greater than 1 at runtime by the application. Used for defining a period to keep the PC awake.</comment>
</data>
<data name="AWAKE_KEEP_INDEFINITELY" xml:space="preserve">
<value>Keep awake indefinitely</value>
<comment>Keep the system awake forever</comment>
</data>
<data name="AWAKE_KEEP_ON_INTERVAL" xml:space="preserve">
<value>Keep awake on interval</value>
<comment>Keep the system awake for a given time</comment>
</data>
<data name="AWAKE_KEEP_SCREEN_ON" xml:space="preserve">
<value>Keep screen on</value>
</data>
<data name="AWAKE_KEEP_UNTIL_EXPIRATION" xml:space="preserve">
<value>Keep awake until expiration date and time</value>
<comment>Keep the system awake until expiration date and time</comment>
</data>
<data name="AWAKE_1_MINUTE" xml:space="preserve">
<value>1 minute</value>
</data>
<data name="AWAKE_MINUTES" xml:space="preserve">
<value>{0} minutes</value>
<comment>{0} shouldn't be removed. It will be replaced by a number greater than 1 at runtime by the application. Used for defining a period to keep the PC awake.</comment>
</data>
<data name="AWAKE_OFF" xml:space="preserve">
<value>Off (keep using the selected power plan)</value>
<comment>Don't keep the system awake, use the selected system power plan</comment>
</data>
<data name="AWAKE_UNCHECKED" xml:space="preserve">
<value>Unchecked</value>
</data>
</root>

View File

@ -105,7 +105,7 @@
<custom:PageLink x:Uid="LearnMore_Awake" Link="https://aka.ms/PowerToysOverview_Awake" />
</custom:SettingsPageControl.PrimaryLinks>
<custom:SettingsPageControl.SecondaryLinks>
<custom:PageLink Link="https://awake.den.dev" Text="Den Delimarsky's work on creating Awake" />
<custom:PageLink x:Uid="SecondaryLink_Awake" Link="https://awake.den.dev" />
</custom:SettingsPageControl.SecondaryLinks>
</custom:SettingsPageControl>
</Page>

View File

@ -2355,6 +2355,10 @@ From there, simply click on one of the supported files in the File Explorer and
<value>Learn more about Awake</value>
<comment>Awake is a product name, do not loc</comment>
</data>
<data name="SecondaryLink_Awake.Text" xml:space="preserve">
<value>Den Delimarsky's work on creating Awake</value>
<comment>Awake is a product name, do not loc</comment>
</data>
<data name="LearnMore_ColorPicker.Text" xml:space="preserve">
<value>Learn more about Color Picker</value>
<comment>Color Picker is a product name, do not loc</comment>